Skip to content

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
        }
    }
}