Weizen Eingießanlage: Unterschied zwischen den Versionen

Aus HSHL Mechatronik
Zur Navigation springen Zur Suche springen
Zeile 163: Zeile 163:
Datei:Simulink-Regler-Final.png| Weizenglas Eingießanlage - Regler - Simulink - [[Datei:Simulink Regler.zip|mini]]
Datei:Simulink-Regler-Final.png| Weizenglas Eingießanlage - Regler - Simulink - [[Datei:Simulink Regler.zip|mini]]
</gallery>
</gallery>
'''read_HX711 S-Function:'''


<div style="width:1100px; height:500px; overflow:scroll; border: hidden">
<div style="width:1100px; height:500px; overflow:scroll; border: hidden">
<syntaxhighlight lang="cpp" style="border: none; background-color: #EFF1C1; font-size:larger">
<syntaxhighlight lang="cpp" style="border: none; background-color: #EFF1C1; font-size:larger">
a
/* Includes_BEGIN */
#ifndef MATLAB_MEX_FILE
 
#include "HX711.h"
 
#define OFFSET 66981
#define SCALE (float) (145173 - OFFSET) / 200
 
HX711 loadCell;
 
#endif
/* Includes_END */
 
/* Externs_BEGIN */
/* extern double func(double a); */
/* Externs_END */
 
void read_HX711_Start_wrapper(real_T *xD,
                              const uint8_T *SCK, const int_T p_width0,
                              const uint8_T *DOUT, const int_T p_width1)
{
/* Start_BEGIN */
#ifndef MATLAB_MEX_FILE
    Serial.begin(9600);
        loadCell.begin((int) DOUT[0], (int) SCK[0]);
        loadCell.set_offset(OFFSET);
        loadCell.set_scale(SCALE);
#endif
/* Start_END */
}
 
void read_HX711_Outputs_wrapper(real_T *force,
                                const real_T *xD,
                                const uint8_T *SCK, const int_T p_width0,
                                const uint8_T *DOUT, const int_T p_width1)
{
/* Output_BEGIN */
#ifndef MATLAB_MEX_FILE
    float f = loadCell.get_units(10);
    Serial.println(f);
    force[0] = (double) f;
    Serial.println(force[0]);
#endif
/* Output_END */
}
 
void read_HX711_Update_wrapper(real_T *force,
                              real_T *xD,
                              const uint8_T *SCK, const int_T p_width0,
                              const uint8_T *DOUT, const int_T p_width1)
{
/* Update_BEGIN */
 
/* Update_END */
}
 
void read_HX711_Terminate_wrapper(real_T *xD,
                                  const uint8_T *SCK, const int_T p_width0,
                                  const uint8_T *DOUT, const int_T p_width1)
{
/* Terminate_BEGIN */
/*
* Custom Terminate code goes here.
*/
/* Terminate_END */
}
</syntaxhighlight>
</div>
 
'''drive_Steps S-Function:'''
 
<div style="width:1100px; height:500px; overflow:scroll; border: hidden">
<syntaxhighlight lang="cpp" style="border: none; background-color: #EFF1C1; font-size:larger">
/* Includes_BEGIN */
#ifndef MATLAB_MEX_FILE
 
#include "DM442.h"
 
DM442 stepper;
 
#endif
/* Includes_END */
 
/* Externs_BEGIN */
/* extern double func(double a); */
/* Externs_END */
 
void drive_Steps_Start_wrapper(real_T *xD,
                              const uint8_T *ENA, const int_T p_width0,
                              const uint8_T *DIR, const int_T p_width1,
                              const uint8_T *PUL, const int_T p_width2)
{
/* Start_BEGIN */
#ifndef MATLAB_MEX_FILE
    stepper.begin(DIR[0], ENA[0], PUL[0]);
    stepper.setDirection(RIGHT);
    stepper.setFrequency(30);
    stepper.start();
}
#endif
/* Start_END */
}
 
void drive_Steps_Outputs_wrapper(const boolean_T *shouldStep,
                                const uint16_T *stepsToDrive,
                                uint16_T *stepsDriven,
                                const real_T *xD,
                                const uint8_T *ENA, const int_T p_width0,
                                const uint8_T *DIR, const int_T p_width1,
                                const uint8_T *PUL, const int_T p_width2)
{
/* Output_BEGIN */
#ifndef MATLAB_MEX_FILE
    if(shouldStep[0]) {
        stepper.setFrequency(stepsToDrive[0]);
        stepper.driveSteps(stepsToDrive[0]);
        long steps = stepper.getSteps();
        stepsDriven[0] = steps;
    }
#endif
/* Output_END */
}
 
void drive_Steps_Update_wrapper(const boolean_T *shouldStep,
                                const uint16_T *stepsToDrive,
                                uint16_T *stepsDriven,
                                real_T *xD,
                                const uint8_T *ENA, const int_T p_width0,
                                const uint8_T *DIR, const int_T p_width1,
                                const uint8_T *PUL, const int_T p_width2)
{
/* Update_BEGIN */
 
/* Update_END */
}
 
void drive_Steps_Terminate_wrapper(real_T *xD,
                                  const uint8_T *ENA, const int_T p_width0,
                                  const uint8_T *DIR, const int_T p_width1,
                                  const uint8_T *PUL, const int_T p_width2)
{
/* Terminate_BEGIN */
/*
* Custom Terminate code goes here.
*/
/* Terminate_END */
}
</syntaxhighlight>
</syntaxhighlight>
</div>
</div>

Version vom 17. Januar 2024, 18:12 Uhr

Autor: Philipp Sander, Dennis Fleer
Betreuer: Prof. Dr. Mirek Göbel


Einleitung

Dieser Artikel beschreibt den Aufbau und die Funktion einer Weizenglas-Eingießanlage. Hierbei gibt es eine Halterung für die Flasche und eine für ein Glas. Beide sind jeweils an einer rotierenden Holzplatte montiert. Diese Holzplatte wird mittels Elektromotor rotiert. Über einem Drucksensor wird der Füllstand des Weizenglases ermittelt und eine optimale Einfüllung des Glases erreicht.

Anforderungen

Teilanforderungen
Nr. Beschreibung Bereich Zuständig
1 Die Halterungen müssen an der Holzplatte befestigt werden. Hardware Dennis Fleer, Philipp Sander
2 Der Motor muss die Holzplatte drehen können. Hardware Dennis Fleer, Philipp Sander
3 Die Elektrik muss eingebaut und verkabelt werden. Hardware Dennis Fleer, Philipp Sander
4 Die Regelung muss durch den Kraftsensor erfolgen. Software Dennis Fleer, Philipp Sander
5 Der Motor muss mittels Regler angesteuert werden. Software Dennis Fleer, Philipp Sander

Funktionaler Systementwurf/Technischer Systementwurf

Im folgenden Systementwurf wird das Projekt in Systemkomponenten unterteilt:

  • Arduino: In Matlab Simulink programmierte Ansteuerung des Motors und Regelung.
  • Motor: Drehbewegung der Holzplattform
  • Drucksensor: Kraftmessung für die Füllstandserkennung
  • Regler: Füllstandsregelung des Weizenglases


Komponentenspezifikation

Nr. Bauteil Beschreibung
1 Arduino MEGA 2560
  • Versorgungsspannung: 7V-12V (empfohlen)
  • Betriebsspannung: 5V
  • 54 digitale Ein-/Ausgänge und 16 analoge Eingänge
2 ADM442 Motortreiber
  • Vollschritt Einstellung
  • Versorgungsspannung 24V
3 HX711 Wägezelle
  • Versorgungsspannung 5V
  • Messbereich: bis zu 5Kg
4.1 Schrittmotor ...
  • Betriebsspannung 3V
  • Haltedrehmoment mind. 1,6 Nm

Umsetzung (HW/SW)

Hardware

Projektübersicht:

In unserem Projekt liegen die Anforderung vorrangig darin eine motorbetriebene drehbare Holzplatte zu konstruieren und dieses System mit einer geeigneten Motoransteuerung zu betreiben. In bezug auf Kosten und Gewicht haben wir uns daher für eine Holzkonstruktion entschieden. Die Holzplatte, an welcher die Halterungen für die Bierflasche und Weizenflasche sowie der Sensor befestigt ist, wird von einer Massivholzwelle getragen. Diese Welle wird mittels Lageraufständen auf einer Holzgrundplatte befestigt. Die Welle wird durch eine Riemenübersetzung mit dem Schrittmotor angetrieben.

3D Ansicht:

Baugruppen Model

Motor:

Wir wollten zunächst den Motor des Arduino-Mega-Sets verwenden. Allerdings ist uns nach einer kleinen Testfahrt aufgefallen dass dieser zu wenig Haltedrehmoment aufweist. Daher haben wir auf einen ausgediehnten Motor aus unsere Partnerfirma "Diebold-Nixdorf Inc." gesetzt. Dieser Motor war nun auch in der Lage unsere Anforderungen zu erfüllen. Um diesen Motor zu betreiben wählten wir einen Motortreiber welchen wir ebenfalls in einem ausgediehnten Geldautomaten-System fanden.

Konstruktion:

Die Konstruktion der Halterung ist auf den ersten Blick sehr simpel. Dennoch galt es für uns die Kosten sowie das Gewicht niedrig zu halten. Daher belaufen sich fast alle Komponenten auf Holz und Kunststoff. Für die meisten Komponenten konnten wir auf unser Betriebsinternes Lager zurückgreifen lediglich die Holzplatte und die Halterungen für Flasche und Glas waren noch nicht vorhanden. Die Halterungen für Glas und Flasche wurden durch einen 3D-Kunststoffdruck gefertigt. Zudem mussten wir uns überlegen wie wir die Flasche in der Halterung befestigen. Um auch hier eine günstige, einfache und leichte Lösung zu erreichen, setzen wir auf die Spannkraft zweier Gummis, welche die Flasche im Halter halten.

Wägezelle HX711:

Da die Wägezelle über die physikalische Kraft der Gewichtskraft funktioniert, war es eine Herausforderung in unserem drehenden System die korrekten Werte für den Füllstand zu erhalten. Dies war deshalb so schwierig weil sich die Wägezelle immer in einem anderen Winkel zur Gewichtskraft des Füllstandes befindet. Aus diesem Grund mussten wir die Messwerte noch einmal mit dem cos des Winkels multiplizierten um die korrekte Gewichtskraft zu erhalten. Wir verwenden außerdem einen Look-up-Table um uns die Verarbeitung der Messdaten zu vereinfachen. Konkret subtrahieren wir unseren gemessenen wert mit dem Wert aus dem Look-up-Table an der gleichen Winkelstellung. Somit Erhalten wir die korrekte Gewichtskraft des Pegelstandes des Glases. Dies ist dann dementsprechend unser IST-Wert.

PI-Regler:

Der IST-Wert wird nun mit dem SOLL-Wert von 500 (500ml/Kg) subtrahiert. Somit erhalten wir unsere Regelabweichung welche wir weiterhin mit dem PI-Regler verarbeiten. Aufgrund dessen, dass 1-Motorschritt in 0,39 Grad am äußeren Umfang der Holzplatte entspricht benötigen wir eine sehr schnelle Regulierung der Motorschritte, sobald Flüssgkeit in das Glas läuft. Daher benötigen wir eine möglichst schnelle Sprungantwort und somit einen großen P-Anteil in unserem Regler. Für unser System haben sich die Werte Kp=0,0135 und Ki=0,00675 als praktikabel erwiesen. Die Stellgröße des Reglers wird direkt als Ansteuerung für den Motor genutzt.

Motoransteuerung:

Die Motoransteuerung erfolgt über den Motortreiber DM441 dieser braucht eine externe Versorgungsspannung von 24V. Außerdem werden zur Steuerung drei Pins angeschlossen.

- ENA: Sorgt für das Starten des Motors und zusätzlich auch für einen Haltestrom.

- DIR: Gibt die Richtung, in die der Motor fahren soll.

- PUL: Über diesen Pin wird ein PWM-Signal gesendet, welches das Drehmoment und die Geschwindigkeit bestimmt.

Verdrahtungsplan:


Software

Programmablaufplan:

Simulink Regler Model:

read_HX711 S-Function:

/* Includes_BEGIN */
#ifndef MATLAB_MEX_FILE

#include "HX711.h"

#define OFFSET 66981
#define SCALE (float) (145173 - OFFSET) / 200

HX711 loadCell;

#endif
/* Includes_END */

/* Externs_BEGIN */
/* extern double func(double a); */
/* Externs_END */

void read_HX711_Start_wrapper(real_T *xD,
                              const uint8_T *SCK, const int_T p_width0,
                              const uint8_T *DOUT, const int_T p_width1)
{
/* Start_BEGIN */
#ifndef MATLAB_MEX_FILE
    Serial.begin(9600);
        loadCell.begin((int) DOUT[0], (int) SCK[0]);
        loadCell.set_offset(OFFSET);
        loadCell.set_scale(SCALE);
#endif
/* Start_END */
}

void read_HX711_Outputs_wrapper(real_T *force,
                                const real_T *xD,
                                const uint8_T *SCK, const int_T p_width0,
                                const uint8_T *DOUT, const int_T p_width1)
{
/* Output_BEGIN */
#ifndef MATLAB_MEX_FILE
    float f = loadCell.get_units(10);
    Serial.println(f);
    force[0] = (double) f;
    Serial.println(force[0]);
#endif
/* Output_END */
}

void read_HX711_Update_wrapper(real_T *force,
                               real_T *xD,
                               const uint8_T *SCK, const int_T p_width0,
                               const uint8_T *DOUT, const int_T p_width1)
{
/* Update_BEGIN */

/* Update_END */
}

void read_HX711_Terminate_wrapper(real_T *xD,
                                  const uint8_T *SCK, const int_T p_width0,
                                  const uint8_T *DOUT, const int_T p_width1)
{
/* Terminate_BEGIN */
/*
 * Custom Terminate code goes here.
 */
/* Terminate_END */
}

drive_Steps S-Function:

/* Includes_BEGIN */
#ifndef MATLAB_MEX_FILE

#include "DM442.h"

DM442 stepper;

#endif
/* Includes_END */

/* Externs_BEGIN */
/* extern double func(double a); */
/* Externs_END */

void drive_Steps_Start_wrapper(real_T *xD,
                               const uint8_T *ENA, const int_T p_width0,
                               const uint8_T *DIR, const int_T p_width1,
                               const uint8_T *PUL, const int_T p_width2)
{
/* Start_BEGIN */
#ifndef MATLAB_MEX_FILE
    stepper.begin(DIR[0], ENA[0], PUL[0]);
    stepper.setDirection(RIGHT);
    stepper.setFrequency(30);
    stepper.start();
}
#endif
/* Start_END */
}

void drive_Steps_Outputs_wrapper(const boolean_T *shouldStep,
                                 const uint16_T *stepsToDrive,
                                 uint16_T *stepsDriven,
                                 const real_T *xD,
                                 const uint8_T *ENA, const int_T p_width0,
                                 const uint8_T *DIR, const int_T p_width1,
                                 const uint8_T *PUL, const int_T p_width2)
{
/* Output_BEGIN */
#ifndef MATLAB_MEX_FILE
    if(shouldStep[0]) {
        stepper.setFrequency(stepsToDrive[0]);
        stepper.driveSteps(stepsToDrive[0]);
        long steps = stepper.getSteps();
        stepsDriven[0] = steps;
    }
#endif
/* Output_END */
}

void drive_Steps_Update_wrapper(const boolean_T *shouldStep,
                                const uint16_T *stepsToDrive,
                                uint16_T *stepsDriven,
                                real_T *xD,
                                const uint8_T *ENA, const int_T p_width0,
                                const uint8_T *DIR, const int_T p_width1,
                                const uint8_T *PUL, const int_T p_width2)
{
/* Update_BEGIN */

/* Update_END */
}

void drive_Steps_Terminate_wrapper(real_T *xD,
                                   const uint8_T *ENA, const int_T p_width0,
                                   const uint8_T *DIR, const int_T p_width1,
                                   const uint8_T *PUL, const int_T p_width2)
{
/* Terminate_BEGIN */
/*
 * Custom Terminate code goes here.
 */
/* Terminate_END */
}

Komponententest

Teilanforderungen
Nr. Beschreibung Testmethode Zuständigkeit Testergebnis
1 Die Halterungen müssen an der Holzplatte befestigt werden. Die Halterungen wurden korrekt befestigt und halten dem Gewicht und der Rotation stand. Fleer, Sander Bestanden
2 Der Motor muss die Holzplatte drehen können. Der Motor kann sowohl beide Gewichte als auch nur die Flasche ohne Probleme heben und halten. Fleer, Sander Bestanden
3 Die Elektrik muss eingebaut und verkabelt werden. Die Verdrahtung der Bauteile wurde korrekt durchgeführt und nochmals mittels Durchgangsprüfung geprüft. Fleer, Sander Bestanden
4 Die Regelung muss durch den Kraftsensor erfolgen. Die Wägezelle misst jede Sekunde die Gewichtskraft des Inhalts. Dieser Ist-Wert wird mit dem Soll-Wert subtrahiert und geht als Regelfehler in unseren Regler. Fleer, Sander Bestanden
5 Der Motor muss mittels Regler angesteuert werden Die Ansteuerung erfolgt softwareseitig durch die Stellgröße unseres Reglers. Fleer, Sander Bestanden

Ergebnis

Das Projekt zur Füllstandsregelung eines Bierglases an der HSHL im Fachgebiet der Mechatronik führte zu einem positiven Ergebnis. Die Anlage ist in der Lage durch umlegen eines Schalters ein 0,5Liter Bierglas einzuschenken. Zu Beginn des Einfüllvorgangs werden die maximalen Motorschritte gefahren. Sobald der Füllstand erkannt wird, werden, je nach Füllstand, weniger Schritte gefahren.

Zusammenfassung

Lessons Learned

Wir haben am Anfang viele Überlegungen getroffen. Aufgrund von Berechnungsfehlern oder falschen Datenblättern haben wir viele Rükschläge erleiden müssen. Schlussendlich konnten wir unseren Anfangs geplanten Ablauf nicht in die Tat umsetzen und sind ziehmlich in Zeitstress gekommen. Daraus haben wir gelernt jedes Datenblatt zweimal zu überprüfen und Berechnungen auch in der Realität auszuprobieren und nicht auf theoretische Annahmen zu vertrauen.

Auch die Programmierung mit Simulink war eine Tortur. Aufgrund unseres Zeitdrucks haben wir uns dann dazu entschieden erstmal ein Arduino Programm zu entwickeln, womit wir immerhin schonmal alles testen konnten und weiter kamen. Später haben wir dann die Reglereinstellungen und Ansteuerungen für Sensor und Aktor in S-Function-Blöcke übernommen und so ein lauffähiges Simulink Modell kreiert. Die Schlüsse die wir hier raus gezogen haben, sind erstmal den vertrauten einfachen Weg gehen und später erst den unkonventionellen Weg nehmen. Auch haben wir gelernt nie wieder auf Matlab Simulink etwas für einen Arduino zu programmieren, da dies um ein viel faches schwieriger ist als ein sauber aufgebautes Arduino Projekt.

In der Programmierung gab es noch ein weiteres Problem. Für den HX711 gab es eine lauffähige Bibliothek schon zur Verfügung. Da wir nicht auf den Anfangs geplanten Motor von Funduino zurück greifen konnten mussten wir einen anderen Motor nehmen. Da dieser Motor eine Anfertigung für die Firma Diebold Nixdorf ist gibt es keine öffentlichen Bibliotheken zur Steuerung. Somit musste hier eine eigene Bibliothek zur Steuerung programmiert werden. Diese musste dann auch wieder getestet und Fehler behoben werden. Auch hier wäre mit mehr Zeit es einfacher gewesen einen Motor zu beschaffen der schon eine fertige Bibliothek öffentlich verfügbar hat.

Projektunterlagen

Projektplan

Projektdurchführung

YouTube Video

In dem folgenden Youtube Video YouTube-Video werden die Funktionen Funktion der Weizeneingießanlage gezeigt.

Video 1: Funktion der Weizeneingießanlage

Weblinks

Literatur


→ zurück zur Übersicht: WS 22/23: Angewandte Elektrotechnik (BSE)