Die umfassende Blender-Video-Tutorial-Serie¶
Wir stellen Ihnen eine ausführliche Blender-Video-Tutorial-Serie kostenlos zur Verfügung, in der das IHK-Mechatroniker-Prüfungsmodell Teil 1 (AP1) Frühjahr 2025 Schritt für Schritt von Grund auf mit Blender modelliert wird.
Mit dieser Serie möchten wir Anwender dazu befähigen, beliebige mechatronische Anlagen eigenständig in Blender zu modellieren und diese anschließend mit PLC-Lab 3D Studio in einen digitalen Zwilling zu überführen.
Der Link zur Youtube Playlist mit allen Videos:
Blender Tutorial Serie auf YouTube
Wichtige Blender Shortcuts als PDF Datei¶
Schützschaltung der AP1¶
Die Schützschaltung für die AP1 wird durch Rechnerobjekte in PLC-Lab 3D Studio nachgebildet. Dazu wird der Skill {Tools} einem beliebigen 3D-Objekt hinzugefügt.
Es werden 4 BOOL-Ausdrücke hinzugefügt:
| Ergebnis-Symbol (Target) | Ausdruck (Expression) | Beschreibung |
|---|---|---|
| KE2 | ([SJ2] or [KE2]) and [SJ1] | Notaus-Schaltgerät KE2 setzen |
| PF1 | not [SJ1] | PF1 leuchtet, wenn Notaus betätigt |
| PF31 | [PF1] | PF31 leuchtet ebenfalls bei NotAus |
| MagnetIstEin | not [QA40] | Magnet ist eingeschaltet |
Hinweis: Bei der Formulierung des Ausdrucks, müssen die Symbole in eckigen Klammern stehen.
Tag-Liste (Symbole für Ein- und Ausgänge)¶
I0.0;KE2;BOOL;Meldung NOT AUS o.k.
I0.1;SJ3;BOOL;Steuerung Ein/Aus
I0.2;SJ4;BOOL;Betriebsart Einricht-/Automatikbetrieb
I0.3;SJ5;BOOL;Start Automatik
I0.4;SJ6;BOOL;Zylinder MM10 'Magazin' einfahren
I0.5;SJ7;BOOL;Zylinder MM10 'Magazin' ausfahren
I0.6;SJ8;BOOL;Zylinder MM20 'Stopper' einfahren
I0.7;SJ9;BOOL;Zylinder MM20 'Stopper' ausfahren
I1.0;SJ10;BOOL;Zylinder MM30 'Magnet' einfahren
I1.1;SJ11;BOOL;Zylinder MM30 'Magnet' ausfahren
I1.2;SJ12;BOOL;Magnet MB40 deaktivieren
I1.3;BP1;BOOL;Betriebsdruck vorhanden
I1.4;BG1;BOOL;Materialerkennung bei Magazin (LWL)
I1.5;BG2;BOOL;Materialerkennung bei Stopper (kapazitiv)
I1.6;BG3;BOOL;Materialerkennung bei Stopper (induktiv)
I1.7;BG11;BOOL;Zylinder MM10 'Magazin' eingefahren (Grundstellung)
I2.0;BG12;BOOL;Zylinder MM10 'Magazin' ausgefahren
I2.1;BG21;BOOL;Zylinder MM20 'Stopper' eingefahren
I2.2;BG22;BOOL;Zylinder MM20 'Stopper' ausgefahren (Grundstellung)
I2.3;BG31;BOOL;Zylinder MM30 'Magnet' eingefahren
I2.4;BG32;BOOL;Zylinder MM30 'Magnet' ausgefahren
I2.5;BI25;BOOL;BI25
I2.6;BI26;BOOL;BI26
I2.7;FC7;BOOL;Motorschutz
Q0.0;MB11;BOOL;Zylinder MM10 'Magazin' einfahren
Q0.1;MB12;BOOL;Zylinder MM10 'Magazin' ausfahren
Q0.2;MB21;BOOL;Zylinder MM20 'Stopper' einfahren
Q0.3;MB22;BOOL;Zylinder MM20 'Stopper' ausfahren
Q0.4;MB31;BOOL;Zylinder MM30 'Magnet' einfahren
Q0.5;MB32;BOOL;Zylinder MM30 'Magnet' ausfahren
Q0.6;QRes5;BOOL;QRes5
Q0.7;QRes6;BOOL;QRes6
Q1.0;PF32;BOOL;Signalsäule Grün 'Materialart Metall'
Q1.1;PF33;BOOL;Signalsäule Weiß 'Materialart Kunststoff'
Q1.2;QA40;BOOL;Magnet ausschalten
Q1.3;PF2;BOOL;Grundstellung
Q1.4;PF3;BOOL;Betriebsart Tipp-/Automatikbetrieb
Q1.5;PF4;BOOL;Betriebsdruck vorhanden
Q1.6;PF5;BOOL;Motorschutz hat ausgelöst
Q1.7;PF6;BOOL;Zyklus ein
Q2.0;PF7;BOOL;Meldeleuchte Magazin leer
Q2.1;PF8;BOOL;Magnet ist deaktiviert
Q2.2;PF10;BOOL;Zylinder MM10 'Magazin' eingefahren
Q2.3;PF11;BOOL;Zylinder MM10 'Magazin' ausgefahren
Q2.4;PF12;BOOL;Zylinder MM20 'Stopper' eingefahren
Q2.5;PF13;BOOL;Zylinder MM20 'Stopper' ausgefahren
Q2.6;PF14;BOOL;Zylinder MM30 'Magnet' eingefahren
Q2.7;PF15;BOOL;Zylinder MM30 'Magnet' ausgefahren
M0.0;MCreatorDisable;BOOL;Merker Creator sperren
M0.1;PF1;BOOL;Meldeleuchte 'Not-Aus' gedrückt
M0.2;PF31;BOOL;Signalsäule Rot 'Not-Aus'
M0.3;SJ1;BOOL;Not-Aus Schalter
M0.4;SJ2;BOOL;Reset Not-Aus Situation
M0.5;QA1;BOOL;Hauptschalter
M0.6;MagnetIstEin;BOOL;Magnet ist eingeschaltet
M1.1;Flag1;BOOL;
M1.2;Flag2;BOOL;
M1.3;Flag3;BOOL;
M1.4;Flag4;BOOL;
MW10;FlagAnalog;INT;
M2000.0;Intern_VoltageIsOn;BOOL;Spannung ist eingeschaltet.
C# Programm zur AP1¶
Inhalt der Program.cs:
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
public class CSharpScript4Model
{
//Inputs and outputs (generated by PLC-Lab 3D)
public bool KE2 { get;set; } //Meldung NOT AUS o.k.
public bool SJ3 { get; set;} //Steuerung Aus/Ein
public bool SJ4 { get; set;} //Betriebsart Einricht-/Automatikbetrieb
public bool SJ5 { get;set; } //Start Automatik
public bool SJ6 { get;set; } //Zylinder MM10 'Magazin' einfahren
public bool SJ7 { get;set; } //Zylinder MM10 'Magazin' ausfahren
public bool SJ8 { get;set; } //Zylinder MM20 'Stopper' einfahren
public bool SJ9 { get; set;} //Zylinder MM20 'Stopper' ausfahren
public bool SJ10 { get; set;} //Zylinder MM30 'Magnet' einfahren
public bool SJ11 { get; set;} //Zylinder MM30 'Magnet' ausfahren
public bool SJ12 { get;set; } //Magnet MB40 deaktivieren
public bool BP1 { get; set;} //Betriebsdruck vorhanden
public bool BG1 { get;set; } //Materialerkennung bei Magazin (LWL)
public bool BG2 { get;set; } //Materialerkennung bei Stopper (kapazitiv)
public bool BG3 { get; set;} //Materialerkennung bei Stopper (induktiv)
public bool BG11 { get; set;} //Zylinder MM10 'Magazin' eingefahren (Grundstellung)
public bool BG12 { get; set;} //Zylinder MM10 'Magazin' ausgefahren
public bool BG21 { get; set;} //Zylinder MM20 'Stopper' eingefahren
public bool BG22 { get; set;} //Zylinder MM20 'Stopper' ausgefahren (Grundstellung)
public bool BG31 { get; set;} //Zylinder MM30 'Magnet' eingefahren
public bool BG32 { get; set;} //Zylinder MM30 'Magnet' ausgefahren
public bool BI25 { get; set;} //BI25
public bool BI26 { get; set;} //BI26
public bool FC7 { get; set;} //Motorschutz
public bool MB11 { get; set; } //Zylinder MM10 'Magazin' einfahren
public bool MB12 { get; set; } //Zylinder MM10 'Magazin' ausfahren
public bool MB21 { get; set; } //Zylinder MM20 'Stopper' einfahren
public bool MB22 { get; set; } //Zylinder MM20 'Stopper' ausfahren
public bool MB31 { get; set; } //Zylinder MM30 'Magnet' einfahren
public bool MB32 { get; set; } //Zylinder MM30 'Magnet' ausfahren
public bool QRes5 { get; set; } //QRes5
public bool QRes6 { get; set; } //QRes6
public bool PF32 { get; set; } //Signalsäule Grün 'Materialart Metall'
public bool PF33 { get; set; } //Signalsäule Weiß 'Materialart Kunststoff'
public bool QA40 { get; set; } //Magnet ausschalten
public bool PF2 { get; set; } //Grundstellung
public bool PF3 { get; set; } //Betriebsart Tipp-/Automatikbetrieb
public bool PF4 { get; set; } //Betriebsdruck vorhanden
public bool PF5 { get; set; } //Motorschutz hat ausgelöst
public bool PF6 { get; set; } //Zyklus ein
public bool PF7 { get; set; } //Meldeleuchte Magazin leer
public bool PF8 { get; set; } //Magnet ist deaktiviert
public bool PF10 { get; set; } //Zylinder MM10 'Magazin' eingefahren
public bool PF11 { get; set; } //Zylinder MM10 'Magazin' ausgefahren
public bool PF12 { get; set; } //Zylinder MM20 'Stopper' eingefahren
public bool PF13 { get; set; } //Zylinder MM20 'Stopper' ausgefahren
public bool PF14 { get; set; } //Zylinder MM30 'Magnet' eingefahren
public bool PF15 { get; set; } //Zylinder MM30 'Magnet' ausgefahren
//-------
//Here you can define your own variables
//these are additional variables
public bool ControlOn; //this is a sample variable you can delete this line
public int Step;//this is a sample variable you can delete this line
private DateTime _dtOld;//this is a sample variable you can delete this line
public string ConsoleString { get; set; }
private DateTime _timerElapsedDt;
private DateTime _timerElapsedTakt = DateTime.Now;
private DateTime _qA40StartDt = DateTime.Now;
private int _hauptprogrammStep = 1;
private int _einrichtBetriebStep = 300;
private int _automatikBetriebStep = 0;
private int _anzeigeStep = 200;
private bool _takt,_qa40Old=false, _SJ12old=false;
private Dictionary<string, DateTime> timerDictionary = new Dictionary<string, DateTime>();
//liefert true, wenn die Zeitverzögerung abgelaufen ist
//operandstring in ein dictionary speichern
//wenn der operandstring in dictionary vorhanden ist, dann die zeitverzögerung prüfen
//wenn die zeitverzögerung abgelaufen ist, operandstring aus dictionary löschen
private bool Zeitverzoegerung(string operandString, bool value, float seconds)
{
// Prüfen, ob der Operand aktiv ist
if (value)
{
// Ist der Operand bereits im Dictionary gespeichert?
if (!timerDictionary.ContainsKey(operandString))
{
// Startzeit speichern
timerDictionary[operandString] = DateTime.Now.AddSeconds(seconds);
}
// Prüfen, ob die Verzögerungszeit abgelaufen ist
if (DateTime.Now >= timerDictionary[operandString])
{
// Operand aus dem Dictionary entfernen und true zurückgeben
timerDictionary.Remove(operandString);
return true;
}
// Verzögerungszeit noch nicht abgelaufen
return false;
}
else
{
// Operand ist nicht mehr aktiv, Timer zurücksetzen
if (timerDictionary.ContainsKey(operandString))
{
timerDictionary.Remove(operandString);
}
return false;
}
}
void TaktErzeugen()
{
if (DateTime.Now > _timerElapsedTakt)
{
_takt = !_takt;
_timerElapsedTakt = DateTime.Now.AddMilliseconds(500);
}
}
void EinrichtBetrieb()
{
switch (_einrichtBetriebStep)
{
case 300:
if (!SJ4)
{
_einrichtBetriebStep++;
}
break;
case 301:
MB11 = SJ6 && !SJ7;
MB12 = SJ7 && !SJ6;
MB21 = SJ8 && !SJ9;
MB22 = SJ9 && !SJ8;
MB31 = SJ10 && !SJ11;
MB32 = SJ11 && !SJ10;
QA40 = SJ12 && _qA40StartDt.AddSeconds(5) > DateTime.Now;
if (SJ12 && !_SJ12old)
{
_qA40StartDt = DateTime.Now;
}
_SJ12old = SJ12;
_qa40Old = QA40;
if (SJ4)
{
_einrichtBetriebStep = 300;
}
break;
}
}
void Anzeige()
{
switch (_anzeigeStep)
{
case 200:
if (SJ3)
{
_anzeigeStep++;
}
break;
case 201:
PF2 = BG11 && BG22 && BG32 && !BG1 && !BG2;//Grundstellung
PF7 = !BG1 && BG11;//Magazin leer
PF4 = BP1; //Druckluft vorhanden
PF5 = !FC7;//Motorschutz
PF8 = QA40;//Magnet deaktiviert
PF10 = BG11;//Zylinder MM10 'Magazin' eingefahren
PF11 = BG12;//Zylinder MM10 'Magazin' ausgefahren
PF12 = BG21;//Zylinder MM20 'Stopper' eingefahren
PF13 = BG22;//Zylinder MM20 'Stopper' ausgefahren
PF14 = BG31;//Zylinder MM30 'Magnet' eingefahren
PF15 = BG32;//Zylinder MM30 'Magnet' ausgefahren
PF32 = BG3 && !BG2;//Materialart Metall
PF33 = BG2 && !BG3;//Materialart Kunststoff
if (!SJ3)
{
_anzeigeStep = 300;
}
break;
}
}
void AutomatikBetrieb()
{
if (_automatikBetriebStep >= 500)
{
MB12 = _automatikBetriebStep == 502;
MB11 = _automatikBetriebStep == 503;
MB31 = _automatikBetriebStep == 505;
QA40 = _automatikBetriebStep == 506;
MB32 = _automatikBetriebStep == 507;
MB21 = _automatikBetriebStep == 508;
MB22 = _automatikBetriebStep == 509;
}
switch (_automatikBetriebStep)
{
case 500:
ConsoleString = "Warten auf SJ5 && BG11 && BG22 && BG32 && !BG1 && !BG2";
if (SJ5 && BG11 && BG22 && BG32 && !BG1 && !BG2)
{
_automatikBetriebStep++;
}
break;
case 501:
if (Zeitverzoegerung("501", true, 1))
{
_automatikBetriebStep++;
}
break;
case 502:
ConsoleString = "Warten auf BG12";
if (BG12)
{
_automatikBetriebStep++;
}
break;
case 503:
ConsoleString = "Warten auf BG2 && BG11";
if (Zeitverzoegerung("BG2", BG2, 2) && BG11)
{
_automatikBetriebStep++;
}
break;
case 504:
if (BG3)
{
_automatikBetriebStep++;
}
else
{
_automatikBetriebStep = 508;
}
break;
case 505:
ConsoleString = "Warten auf BG31 mit Zeitverzögerung 2s";
if (Zeitverzoegerung("BG31", BG31, 2))
{
_automatikBetriebStep++;
}
break;
case 506:
ConsoleString = "Zeitverzögerung 2s";
if (Zeitverzoegerung("505", true, 2))
{
_automatikBetriebStep++;
}
break;
case 507:
ConsoleString = "Warten auf BG32 mit Zeitverzögerung 1s";
if (Zeitverzoegerung("BG32", BG32, 1))
{
_automatikBetriebStep=510;
}
break;
case 508:
ConsoleString = "Warten auf BG21 mit Zeitverzögerung 2s";
if (Zeitverzoegerung("BG21", BG21, 2))
{
_automatikBetriebStep++;
}
break;
case 509:
ConsoleString = "Warten auf BG22 mit Zeitverzögerung 2s";
if (Zeitverzoegerung("BG22", BG22, 2))
{
_automatikBetriebStep++;
}
break;
case 510:
if (BG1)
{
_automatikBetriebStep = 500;
}
else
{
_automatikBetriebStep = 502;
}
break;
}
}
void Hauptprogramm()
{
TaktErzeugen();
EinrichtBetrieb();
Anzeige();
AutomatikBetrieb();
PF3 = false;
switch (_hauptprogrammStep)
{
case 1://Anlage ist aus
_einrichtBetriebStep = 0;
_automatikBetriebStep = 0;
ConsoleString = "Anlage ist ausgeschaltet. Warten auf KE2 && SJ3 && BP1 && !SJ4 && FC7";
if (KE2 && SJ3 && BP1 && !SJ4 && FC7)
{
_hauptprogrammStep++;
}
break;
case 2:
_einrichtBetriebStep = 300;
_hauptprogrammStep++;
break;
case 3://Hand ist aktiv
ConsoleString = "Handbetrieb ist aktiv";
PF3 = true;
if (SJ4)
{
_hauptprogrammStep++;
}
if (!KE2 || !BP1 || !SJ3 || !FC7)
{
_hauptprogrammStep = 1;
}
break;
case 4:
_automatikBetriebStep = 500;
_einrichtBetriebStep = 0;
_hauptprogrammStep++;
break;
case 5://Automatik ist aktiv
PF3 = _takt;
if (!KE2 || !BP1 || !SJ3 || !SJ4 || !FC7)
{
_hauptprogrammStep = 1;
}
break;
}
}
//Definition of helper functions
//these are additional functions
/// <summary>
/// Is called once when the model is started
/// </summary>
public void StartProgram()
{
_hauptprogrammStep = 1;
_einrichtBetriebStep = 0;
ConsoleString = "Meldung aus dem c# Script. StartProgram()";
}
/// <summary>
/// Is called cyclically
/// </summary>
public void LoopProgram()
{
Hauptprogramm();
}
}
/// <summary>
/// Die nachfolgenden Zeilen werden in PLC-Lab nicht benötigt
/// Sie dienen nur dazu, das c# Programm ohne PLC-Lab im Debugmodus zu starten
/// </summary>
class Program
{
static void Main(string[] args)
{
CSharpScript4Model model = new CSharpScript4Model();
model.StartProgram();
while (true)
{
model.LoopProgram();
Console.WriteLine(model.ConsoleString);
System.Threading.Thread.Sleep(10); // Sleep for 10ms
}
}
}