A framework for writing scalable and maintainable ST code
Stage is a framework designed to simplify PLC programming in TwinCAT 3.1. It does not provide pre-made function blocks for analogue inputs or motion components as these you will need to write yourself. It provides scaffolding that allows you to build highly extensible features through automatic registration, discovery and execution.
Check the Wiki page!
- Guides
- API reference
- Changelog
- Obsidian-compatible
Stage requires Beckhoff TwinCAT 3.1, specifically:
- Minimum TwinCAT version: TwinCAT 3.1 - Build 4026
- For TwinCAT system requirements, visit the official Beckhoff TwinCAT System Requirements
-
Clone the repository:
git clone https://github.com/Krystian-L-Lis/Stage.git
-
Import the framework into TwinCAT:
- Open your TwinCAT solution.
- Locate the Core PLC project, expand it by clicking the arrow next to it.
- Right-click on the Core PLC project and select "Save as Library and Install" to add it to the TwinCAT library repository.
- Right-click on References, select "Add Library", and locate the
Coreand/orUtilsunderStagecategory to include it in your project. - For more detailed instructions on TwinCAT library installation, refer to the official Beckhoff guide on Infosys.
- Download the compiled files(
Core.libraryand/orUtils.library) from the release page. - Open your TwinCAT PLC project and navigate to References, then right-click and select "Library Repository" > "Install".
Choose the downloaded.libraryfile to add Stage to the repository. - After installation, right-click on References, select "Add Library", and locate the
Coreand/orUtilsunderStagecategory to include it in your project. - For more detailed instructions on TwinCAT library installation, refer to the official Beckhoff guide on Infosys.
- Automatic dependency injection - register your function block for others to discover at runtime.
- Automatic execution - register function blocks and execute them on an assigned thread.
- Workers - define jobs, start them, and execute them until completion on an assigned thread.
- Utilities - result helpers, string builders, path identifiers, time helpers, math helpers, and color builders.
This guide shows the normal Stage wiring pattern: call Plant.Run() once from the main PLC program, register cyclic function blocks with Execute, register discoverable function blocks with Entity, and register startable procedures with Worker.
FUNCTION_BLOCK SystemTime IMPLEMENTS I_Execute, I_SystemTime
VAR
_exe: Execute(THIS^);
_ett: Entity(THIS^);
nUnixTime: ULINT;
END_VAR
METHOD Execute
nUnixTime := GetUnixTime();
Execute(THIS^) registers the function block for cyclic execution. Entity(THIS^) makes it discoverable through interfaces that extend I_Generic.
PROGRAM MAIN
VAR
SystemTime: SystemTime;
Safety: Safety;
END_VAR
Plant.Run();
VAR
iEtt: I_Entity;
iSystemTime: I_SystemTime;
END_VAR
WHILE IsOk(Plant.NextEtt(iEtt)) DO
IF __QUERYINTERFACE(iEtt.Raw, iSystemTime) THEN
// Use iSystemTime here.
END_IF
END_WHILE
FUNCTION_BLOCK FindBelt IMPLEMENTS I_Job, I_Procedure
VAR
_worker: Worker(THIS^);
_ett: Entity(THIS^);
END_VAR
METHOD JobInit
// Reset procedure state.
METHOD JobExecute
// Run one step per worker cycle.
IF bComplete THEN
_worker.Stop();
END_IF
METHOD JobExit
// Publish final state and clear command bits.
Start the procedure from another function block:
_result := StartConveyors.Start();
IF IsOk(_result) THEN
// The job was accepted by its thread.
END_IF
{attribute 'global_init_slot' := '49000'}
PROGRAM FAST
VAR
Thread: Thread;
END_VAR
Thread.Run();
Assign cyclic work to the fast task during initialization:
FUNCTION_BLOCK SerialComs IMPLEMENTS I_Execute, I_SerialComs
VAR
_exe: Execute(THIS^) := (Thread := FAST.Thread);
_ett: Entity(THIS^);
END_VAR
Contributions to the Stage framework are welcome!
Feel free to fork the repository and submit pull requests.
- Fork the repository and create a feature branch.
- Submit pull requests for review.
- Discuss your ideas by opening an issue before making major changes.
This framework is in its early stage and requires extensive testing!
This project is licensed under the MIT License - see the LICENSE file for details.
If you have questions or suggestions, feel free to reach out via:
- GitHub Issues: Submit an issue