Skip to content

Modules, Submodules, and Components

The idea of the modules is to logically separate the parts of the machine into controllable pieces based on their mechanical and functional dependencies. The hierarchy used helps to further separate the modules into logical processes that can operate independently or together as a single unit.

The PackML standard defines both a Machine Module and an Equipment Module. The purpose of the Machine Module is to act as the communication point for other Machine Modules on other machines working together on the same production line. This enables the possibility of a downstream machine sending a Stopped status up the line so that a machine can enter its Suspended state. The Machine Module is also responsible for sending commands to its Equipment Modules and monitoring their status.

The definitions and functionality of a Machine Module and Equipment Module can be unified under the same function block. Therefore, within the SPT Framework we use FB_PackML_BaseModule as the base of all modules, whether they be the Machine Module (MM) or an Equipment Module (EM). According to the Pack ML standard it is possible for an EM to contain other EMs, acting similarly in function to the MM. Due to this similarity the SPT Framework employs a concept of Modules and Submodules. Each of these extends the functionality provided by the FB_PackML_BaseModule. It is the location of the declaration that will define the Module or Submodule hierarchy. It is important to recognize that the PackML documentation will use the term Equipment Modules, the SPT documentation and code comments will refer to Equipment Modules and Submodules interchangeably, and the code will only refer Submodules.

These Modules and Submodules will each have their own state machine. By default, they will follow the state machine of the module they are defined within, but it is possible for each module to be in a different state and / or mode. So, while the majority of a machine’s modules might be in Automatic / Idle, some EMs might be in Homing / Execute. The machine could also be designed where all EMs go to Homing / Execute and the EMs that do not require homing simply have no logic to perform other than reporting their status to an upper-level module. This type of design decision is to be decided by the programmer as they are not defined by the standard.

Each of these Modules, whether Sub or not, may contain Components (including the Machine Module). Components are the more specific interactions that happen while in a specific Mode and State, such as an Axis, Cylinder, Stack Light, Message Logging, Heating Element, Safety Monitoring, etc. Any module may contain 0,1 or multiple components. Components do not have a state machine defined by the PackML standard but should instead follow any commands issued by the module based on its state machine. Components can however have their own unique state machine internal to the component. A component is not always as simple as a single cylinder or axis, there is also the possibility to create a more complex component. The situation could arise that a machine needs several cylinders to work together in unison, and for this purpose it could be advantageous for a single component to contain multiple cylinders that will respond to a single extend or retract command. However, the argument could also be made that each cylinder should be able to act individually when in manual, and the programmer will have to determine the best way to accomplish this feature request.

Components are responsible for managing their own error handling; and should be self-contained code parts, that are reusable without the PackML state machine or the SPT Framework. This will allow for the most flexibility, adaptability, and reuse in the future. Each component should be able to stand alone as its own entity.

Machine

1
Machine : FB_Machine EXTENDS FB_PackML_BaseModule
The top level of the hierarchy is the Machine Module which we typically refer to as the Machine or Machine Module (MM). The module will extend the FB_PackML_BaseModule from the SPT Base Types library. This will give the Machine function block all the functionality within the methods and properties of FB_PackML_BaseModule. This includes the CyclicLogic() and Initialize() methods which are key parts of the SPT Framework. Within the Machine function block instance, we will declare an instance of each Equipment Module that the Machine is responsible for controlling directly. Likely this will be all of the EMs, but there will be exceptions when Submodules are grouped together under another Equipment Module. The Machine may also directly contain some Components, such as a Stack Light, a pressure switch for machine air, the safety monitoring code, a connection to the recipe database, or many other items that don’t need a state machine that is separate from the Machine Module.

Because of the way that the SPT Framework works behind the scenes, it is not necessary for each module to have its own method for each state. For example, not all Equipment modules will need a Held state, therefore it does not need to exist only to call its parents method (using Super). However, if the EM needs to do something in addition to what the base class does, then the method can be added to the EM, the unique code can be added, and then the method can call its Super at the end of the method (or any other place depending on what is being done in the code).

Note

While a method does not need to be added just to call the SUPER, if the FB is going to be inherited again (grandchild), then any method overridden by the grandchild will need to be added to the child and it's SUPER called, in order to allow the grandchild to call the base method of the original class.

Controlling the EMs

From the Machine Module, when a transitional method (Acting State) of the state machine is called (Resetting), it is standard practice to call Super^.Resetting() at the end of the method. The code in the Resetting() method of the base class will then run. The code in FB_PackML_BaseModule.Resetting() will loop through all the Submodules and pass along the commands required in order to move the state machine of each Submodule into Idle.

If the programmer wishes to control the state machine of the EMs separately from the Machine Module, this can be done by not calling the Super^.Resetting() method. In this way the EM can be controlled independently of the MM. To be clear, this applies to all methods, in order for the EM to act independently of the MM or a higher-level Submodule, simply do not call the Super from the independent Submodule.

Note

We are discussing two different hierarchies here, both the MM/EM/Submodules, and the Base/Child/Grandchild classes. The call to the Super is within the hierarchy of the Base/Child/Grandchild class. The core code to advance the state machine forward is within the FB_PackML_BaseModule, therefore when making an EM/Submodule that has an independent state machine it is the call to FB_PackML_BaseModule (Base) that we don’t want to make.

The methods for the Primary or Waiting states do not contain any code in the base class. Therefore, all code to be processed must be placed in the method of the Machine Module or Equipment Module.

Monitoring the EMs

The FB_PackML_BaseModule has a method named SubModuleMonitor(), likewise there is an equivalent method for ComponentMonitor(). These methods are responsible for detecting when an EM or Component has an Alarm or Event that needs a response, such as an E-Stop or a controlled stop. Imagine the machine has an unwind with a sensor for the end of the roll. When the sensor detects the end of the roll, it will set the event to TRUE within the Component. The ComponentMonitor() method of the EM can then respond by issuing a Change State command of Suspend to itself in order to go to the Suspended state. The Machine Module will also be calling its SubmoduleMonitor() method and will detect that an EM has entered the Suspended state and then command all other EMs to also enter the Suspended state. This monitor and response will be covered again in more detail in the Alarm and Events document, but for now what is important to understand is that the code within the methods is isolated to a single purpose. There is no code for error detection within the waiting or acting states, and there is no code for issuing hardware commands in the error detection.

Giving Data to EMs

The Equipment Modules are going to need some configuration data that might be based on physical machine measurements, station configuration, or product specific values. It is best to configure the EM to use Properties if these values are being provided by an external source. These properties can be used in one of the following ways: directly provide each value through multiple properties, an instance of a structure that contains several values, a location for the EM to read its values from (such as a file or database location); or if the Machine Module has already retrieved the values from a file or database, then it can provide the property of the EM with a pointer or reference to where that data is available. For now it is important to start thinking about passing data between classes or functions blocks using properties and not through VAR_INPUT and VAR_OUTPUT.

Exchanging data between EMs

There are multiple ways for the EMs to communicate with each other. As mentioned above, the most direct way is by using properties. A property of one EM can be read by another EM, or by the Machine Module. If the Machine Module is set up to read specific properties from EMs, then it can have one method for reading a value, and another method for writing the value to the EMs that need that data. The problem with this is that this code in the Machine Module must be maintained to work with any changes in each EM, and the EM code becomes less portable.

Using some form of a pointer to reference the actual location of the data is both more efficient for the CPU and the Memory, it also creates code that is more portable. Think of it this way, instead of passing all the values from one EM to another and therefore creating a second copy of that data, we can simply pass a memory address to the other EM to let it know where to find the data.

This has multiple benefits:

  1. There is only one copy of the data, this uses less memory and if the data changes, then all EMs have access to the new values at the same time without having to be told the values changed.
  2. When the structure of the data changes (new variables added), only the code that will use the new variables has to change, the code that shares the data doesn’t need to.
  3. One of the great benefits is portability, by passing the address of the data in a property, the EM can be easily reused and plugged in to other EMs, even within another project.
Interfaces

One of the best ways to make use of passing addresses instead of data is by implementing Interfaces. Interface pointers (or simply Interfaces) provide several benefits, but the important parts for now are the structure of the data and the address where the data exists. When you define an interface, it is simply a blueprint of the structure or layout of the data. We formalize it (make it specific) by adding methods and properties to it, but in its simplest form it’s just an overlay or a map of how the code should interpret the data, you can think of it as the instructions on how to use the data.

The second part of an Interface comes into play when we use it. This is when we assign an instance of an interface to a memory address. This is no different that any other variable declaration. In its basic form, a variable is a name given to a location in memory that stores a value. An instance of an interface is still a name given to a location in memory that stores a value, but in this case the value is not simply an integer or structure, but instead is a more complex data type that needs some custom instructions on how to use it. Those instructions are contained within the methods and properties of the Interfaces implementation.

Taking things one step further, each instance of the interface creates its own set of those instructions. While the names of the methods and properties are defined in the generic interface, the actual instructions are left to the specific implementation where the interface is used. For those new to OOP and Interfaces this can be a bit overwhelming, the labs will help explain things in a more step by step process. For now, one great example of this is the Homing routine used by the SPT Motion Control library. The FB_BasicAxis has a default homing routine built into the block, but we also have the option to define a homing sequence of our own design and then use an Interface to ‘point’ the FB_BasicAxis to our homing sequence and use the code there as the homing routine instead of the default.

Observer Pattern

A specific design pattern exists for our use case of sharing data between modules. Although the cyclic nature of the PLC provides a way to have some of this functionality without fully implementing the pattern, it still provides us with a well-recognized coding practice. The Observer pattern is typically used in PC programming when a piece of code (a class) needs to receive updated information from another class when the data changes. The full implementation of the Observer pattern allows for a class to connect and disconnect at run time. A simple example of this would be a Bluetooth client for a weather station. Imagine having a weather station that allows you to connect via Bluetooth. Due to the limited range of Bluetooth you will not always be connected to it and therefore there is no need for it to send updates. So, when the Bluetooth connection is established, the client will register with the weather station. The station is known as the Observable, and the phone would be the Observer. Once the Observer is registered to the Observable, the Observable will send notifications to the Observer(s). It is possible for the Observable to send the new data, or to simply send the notification and let the Observer handle retrieving the new data.

Within the SPT Framework we partially implement this when we register Submodules and Components to a Module in the Initialize() method. Each Submodule or Component is an Observer of the MM or EM that it is registered to, and the MM and EMs are the Observables. The code in the base of the Framework adds each EM to the array ipSubModules. We can then use this array to loop through all of the Submodules (Observers) and send them commands or notify them of a change at the same time. The true Observer pattern allows for Observers to come and go, but in this use case we are not expecting any of the EMs to be detachable from the overall control of the machine. If this is a feature that is needed, it can be added by extending the base class to suit your needs.

Exchanging data with MMs on other PLCs

The PackML standard uses PackTags to define a common set of Command, Status, and Admin structures. The idea is to allow multiple different companies to build a machine in their own way, but then provide a standard data format by which they will be able to exchange information. It was previously mentioned that a machine in a production line could stop and then need to transmit that status upstream for other machines to not send product downstream, and to accurately log why they stopped. By populating the PackTags the data can be made available to other Machine Modules that will allow them an access point to both send commands and read status information from another machine, while keeping the internal proprietary control code abstracted and isolated from other companies.

Components of the MM

Components in general are the building blocks that allow us to make connections between the State Machine and anything that is outside of the PLC. Whether it’s a cylinder, an axis, a stack light, or something non-hardware like a database. The simplest implementation of the SPT Framework would be a Machine Module with a single component, and this will be one of the labs we do early on. Components do not have a state machine defined by the standard, but within the SPT Framework they must extend the FB_ComponentBase. This allows them to be a part of the Framework and provides the minimal CyclicLogic() and Initialize() methods that are necessary. Beyond that the commands, status, and configuration of a component are up to the programmer to implement as needed.

Equipment Modules

EMs are defined by their mechanical and functional dependencies. It would typically be the way we group a machine. A simple machine might have an Unwind, a Process and an Outfeed. Each of these could be an Equipment Module. But what if the process station is 2 axes, or has a cylinder before the axis? Then it’s possible that the process station EM could have Submodules, or each of these could be an EM of the Machine Module. How do you decide on architecture? The effective solution is the one that considers the state machine needs of the EMs. If all of the stations can and should follow the same state machine, then they could possibly be implemented as Components of a single EM. But if there could be a need for one of them to be in a different state or mode then it should be placed within its own EM. Another consideration is Portability. If there is a possibility that another machine design will need an independent EM, then some thought should be given to how the EM design choices will impact that design. If one machine had a station with a cylinder and an axis that could function under the same state machine, but another machine would need them to be independently controlled, it might make sense to separate them into their own EMs. When they are working together under one state machine, they can both be controlled by commands from the MM.

Does the component need its own state machine?

A component follows the commands of the EM that it is defined within. These commands are driven by the EMs state machine. For example, we might extend a cylinder in Production.Starting, monitor its position in Production.Execute, and retract it in Production.Completing. If another component will always operate within the same state machine as this component, then we could consider placing them both within the same EM. For example, 2 cylinders that operate on the same mechanical assembly. There is no need to look through the components of the machine and try to find ways to group them together, but instead we should consider when separation is necessary and advantageous. It could be that a component has a unique process that will require it to have its own state machine that is separate from any other on the machine. It is possible that a heating component will need to preheat before the other EMs can go into Production mode. By placing the heating component in its own EM, its mode and state can be completely controlled by its own internal state machine while the other EMs remain in Production.Idle, Production.Starting, or any other mode and state.

Does the component follow the state machine of another component?

There will be components that follow the same state machine and always work together. Some of these will have mechanical connections that force them to work together, while others will simply need to interact synchronously to achieve the desired outcome. While these components can be placed within the same EM it is important to consider how these components will be controlled. If we have a clamp that is activated by a cylinder, then that clamp could be a component of an EM. If there is a long bar with a clamp and cylinder at each end then these two will be connected mechanically and could therefore be designed as a dual cylinder component within an EM, because we should never move one cylinder without moving the other. But what if there is no mechanical connection? What if we have 4 clamps on each side of a table and we want the recipe to decide which clamps to use based on the size of the part? Do we want to control all clamps with a single command, or do we want the option to open and close each one independently? By answering these questions, we can start to see how some components will need to be grouped together, while others must be separated as either individual components or possibly as individual EMs.

Will the component or EM need to change modes independently?

In addition to a separate state machine, it could also be that a component has need to change modes separately from another component. While components might generally operate together, it could be that in a special case that a component needs to change modes to perform a unique function. In this case it would be suggested to create a separate EM for this component.

SubModules

When are submodules needed?

While all EMs are programmatically Submodules of the MM, there is the possibility for an EM to have a Submodule, and for that Submodule to have a Submodule. While these more complex Submodules are possible there are few times when they are needed. The idea of being able to have independent state machines at this many levels requires some planning. Typically, the use case for this is when two EMs are serving the same purpose, but only one is being used at any given time. For example, if a machine has two Unwind EMs that it will alternate between, then a Supervisory EM for the Unwinds could hold two instances of an Unwind EM, where one is in production and feeding material into the machine, and the other is in manual while the material roll is being replaced.

It could also be that you want to group EMs together for the purpose of programmatically isolating them from other EMs. When hot connect groups are used, it could be that all those EMs are grouped together under one larger EM for the purpose of enabling and disabling the hot connect group. It could also be that on a more modular machine design, a group of EMs can be replaced with a different group of EMs depending on the product. This could also be a use case for a group of EMs and therefore create an easier way to integrate that single larger EM into the remainder of the machine.

Components

Components are the way in which we make a connection between the PLC and anything outside of the PLC, whether it be a Virtual or Real Axis, a cylinder, or a database. We use components to receive commands from the control code and then manage the device of the component. It is important to understand that a component does not have to be used within the PackML state machine, or within the SPT Framework. A component should be able to exist on its own within any project. Ideally components can be declared within any project and reused as needed.

Setting values in a component

Using properties and parameters we can configure a component for a specific use case. This could be the number of cylinders within the component, the home position of an axis, or the recipe value for the temperature of a heating element. It is preferable to not have any literal values within the component and instead set those values from outside using either parameters or the control code.

Exchanging data between components
When a component needs to send or receive a value it can be handled by the CyclicLogic() method of the EM that it is declared within. The process and options are no different than how the EMs exchange data with each other.