In this first tutorial we will introduce some key koncepts of VIGO6 which will help you build your first control component. The tutorial alternates between information and "hands on" exercises using the information just presented and supported by "how-to"-live demonstrations. These demonstrations are identified by this icon:
Now - let us get started.
COPP types are expressed within the VIGO6 Active Editor in a tree structure, similar to the navigation pane in Windows Explorer. A component type is identified within the VIGO6 navigation tree with a C icon.
Navigation in the VIGO6 navigation tree is done with the 4 arrow keys or the mouse.
It is possible to have multiple types open at the same time. These are represented as separate tabs in the editor.
A COPP component is a combination of program code, data and configurations defining a specific functionality. A COPP component has memory containing variables and constants, using various memory categories.
<company identifier>_<ID number>-<version number>.
New component types can be created by inheriting from an existing component type.
The existing type is called an Ancestor. The new types are called Descendents. The decendents receive a new ID-number and hence also a new GUID.
Additional methods and facilities can be added in descendents.
The editor ensures that the descendent retains all its ancestor’s properties in order to remain compatible.
The parameter type for the ancestor’s methods cannot be changed.
Versioning and archive
An Archive system is an integrated part of VIGO6. All COPP types are stored in the COPP archive, identified by the GUID. Each type contains COPP information and related documentation.
Any change of an archived type is given a new version by the editor and server.
When you have defined a type, you can use it over and over again. When you use your component in a project, you are actually using an instance of the component type. You can add as many instances of a type as you need.
When a new version of a component type is available, the programmer can decide whether or not to update his instances of the type. No reprogramming is needed.
Now let us start working in VIGO6.
What you need to build - control logic:
The task of the component (shown in light green in the illustration) is to regulate a temperature to a temperature specified in a Setpoint, by controlling an output connected to a heating element. The temperature is measured by a 4-20 mA temperature transmitter. The regulating principle is a simple on/off with a temperature hysteresis. The regulating interval is controlled by a pre-built timer-function.
Important note on naming. Whenever you need to name a new type, the tutorial will indicate the name like this "XX_Temperature_regulator_simple". Please select two letters that make sense to you like your initials (JD for John Doe) and put instead of the XX -i.e. "JD_Temperature_regulator_simple".
Step 1: Create a temperature regulator component
- Open PD_7664 Process_component, by clicking on the "open type"-icon (or pressing CTRL-O"). Then select "COMPONENTS>>". You can now type any part of the name; including numbers and you should be able to see the component on the list. Double click to open.
- Right click on the component name and select “Create new type”. A new tab will open, showing the new component type and you will be the writer. The component is inherited from PD_7664.
- Double click on the name of your component and change it to "XX_Temperature_regulator_simple".
TIP: pressing the space-bar will create an underscore.
Variables can be volatile or non-volatile. Volatile variables lose their value on power-off. Non-volatile variables keep their value even after power-off, and can have a default value assigned.
Variables are local to the component or method in which they are declared. Should it be necessary to set or view the variable outside of the component, the variable needs to be connected to a Register.
Data instances are normally associated with a "quantity type", to simplify visualisation, and to enable the compiler to prevent program-errors related to quantity and thereby help the programmer to avoid quantity errors.
Examples of Quantity types are:
Density, Pressure, Energy, Volume, Mass, Time
When defining variables of floating point type, the Quantity type must be stated.
The Quantity type for the result of a calculation or expression is deduced by the compiler. For any assignment, the compiler analyzes the Quantity types and indicates when there is an incompatibility such as: Volume: = Density.
Create the following variables and constant and add Quantity:
Non-volatile variables section: Set_point_value [AbsoluteTemperature] (PD_2003 Float32) Used as set-point for the regulator. Set the default value to 25 [degrees celcius]
Volatile variable section: Actual_temperature_value [AbsoluteTemperature] (PD_2003 Float32). Holds the value of the input from the temperature component
Instance constants section: Regulating_interval [TimeDifference] (PD_2003 Float32) Defines how often the regulator must run.
Handling local unit definitions
All data in a COPP component is stored in SI-units. Human interfaces as e.g. display and editor converts from the SI units to the unit definition selected via the Local Unit table where a set of units are defined. Eg there is a local unit table for Europe and another for the US. The programmer may prefer to work with gallons while the operator prefer to see litres. This is no problem when using VIGO6.
Step 3: Setting the local unit table in the Active Editor
Click on "Change editor setup" (the orange wheel).
Click on the combo box "Default Quantity Local unit relation table".
Select: PD_5311 Europe_metric_system.
Note: the units that the operator will see is chosen at a later stage in the tutorial series (tutorial 2). For now what we have set is the units used in the editor.
A subcomponent is a special type of component, created and designed by Proces-Data to be integrated into another component (the Parent component). A Subcomponent specifies an interface and a number of data instances. It contains methods with access to its own declared data structures. By Override, the methods in the subcomponent can obtain access to the data in its Parent component. When a component as parent integrates a Subcomponent, the Parent component has direct access to data in the Subcomponent.
Examples of subcomponents are Registers and Timers.
Notation for accessing a register is the same as used to access variables. For example "My_register:= 27" will call the registers Set method, which will store the value "27" in the variable related to the register.
Step 4: Add subcomponents - registers and timer
Make the variables: Set_point_value and Actual_temperature_value visible outside of the control component - eg for the visualisation or for other components.
Right-click on the Subcomponent section of your component and select:
Add>>, Register>> click on PD_4050 Register.
Change the name of the new register to "Set_point".
Then right click on the register and select: "Assign data field to the register subcomponent" and select "Set_point_value" as register variable. Make sure that "get" and "set" is enabled for all user types (this tells the visualisation that this variable must be editable). Set maximum value to 40 and minimum value to 20 (enter the same values for alarm limit high and alarm limit low).
Then create a register (called Actual_temperature) for the variable Actual_temperature_value in the same way. Make sure that "get" is enabled and "set" is disabled for all user types. This tells the visualisation that this variable must be visible but non-editable. Set maximum value to 100 and minimum value to 0 (enter the same values for alarm limit high and alarm limit low).
Add a timer so you can repeat your regulation at predefined intervals:
Add PD_4404 Timer_subcomponent to the Subcomponent section.
Change the name to Timer.
Then select the timer and read the functionality for a Timer_subcomponent by selecting the methods and reading the documentation shown just to the right of the VIGO6 navigation tree.
The connector is a "placeholder" for a connection to a component of a given type. At this point in time we do not specify hardware, we simply specify that we will use hardware compatible with the COPP type that we have chosen to create a connector to.
The decision on specific hardware modules for the components is not made at this point, which gives us the possibility to use the same control component with many (compatible) types of hardware without need for programming control code or visualisation for each.
If eg. a specific hardware module for output control is no longer produced, we simply need to substitute the physical module and our plant will continue to operate with no need for reprogramming or even recompliation.
Step 5 : Add connectors
Your temperature regulator component will need to interface with already made components for reading a temperature (the orange component on the drawing to the left) and for setting a digital output (the blue component on the drawing).
Hence you need to add connectors.
- Create connection to the output component:
Under section "Connection to external component": Add connector to instance of type: PD_2824 Digital_output_base, which is a basis for more output types.
Rename it to Output.
- Create connection to a temperature component: Under section "Connection to external component": Add connector to instance of type: PD_2854 Temperature_input_base rename it to Temperature.
Methods contain program code that only runs when the method is called. It is similar to a function in PROCESS-PASCAL, with the possibility of having parameters and a result.
Program code in a method has direct access to parameters, local variables, component variables and constants. However, methods differ from functions, as they can be called via P-NET.
Methods marked External can be called from another component in the same device or via P-NET. External methods are not allowed to call methods in other components.
Methods marked Internal (I) cannot be called from another component but are allowed to call methods in other components.
See the overview of method calls below:
There is no mutex that encompass both internal and external calls, so be very aware when declaring IE methods as conflicts in execution may arise.
Assignment of a value to a variable
On the left of ’:=’ the name of the variable you want to assign a value is written.
On the right side is the value which can be:
Assigning a constant to a variable with a specific Quantity requires the constant is given the correct local unit (SI unit.)
Example: Weight_Setpoint: = 35 [Kg]
The compiler checks that both sides have compatible data types (GUID match). It also checks that the Quantity type is correct.
Placing the cursor in the beginning of a code line or just after the last text, a popup menu will show the choice of acceptable program code at that position. It is thus not necessary to learn the whole syntax up front.
Through the popup menu it is also possible to access code templates that pre-load control structures.
- Indentation - representing"BEGIN"
- Reverse indentation - representing "END"
An Indented program is like a tree structure in which the indents indicate the level structure of the coding. The editor inserts the vertical lines and highlights the current block to improve readability.
THEN and ELSE are a sub-structure to IF and are thus indented. THEN and ELSE are alternatives and therefore have the same indentation level. THEN and ELSE sub-structures are indented. The IF, THEN, ELSE block is displayed with”+ / -” used to show/hide the block.
The Program Editor has a built in "code standard" that provides the same indentation style, and look. This means that programmers can easily understand each other's programs.
Step 6: Add a method and write your control code
You now need to write the actual piece of code that will enable your component to make the required regulation.
Create a new method : right click on the method section and select Add Method. The new method is renamed to Regulate.
Write code for your temperature control:
Read the temperature from the input component into the register "Actual_temperature" in the control component.
if the temperature is lower than the set point, then open the output
in all other cases close the output
What your code should look like:
When defining a method’s parameter and result type, the name, data type and Quantity type must be defined (as for a variable).
A method call must contain the individual parameters by name.
X: = Component Name. Method Name (Content: = delivered_amount, Number: = 7)
The Editor contains template functionality, which writes the parameter names, for example: Method Name (Content: =?, Number: =?)
A programmer need not remember the order of method parameters, as this will be clear from the parameter names, and leads to a reduced number of errors. (A pop-up menu will only show the identifiers that represent instances of a permissible data type and Quantity type). This model means that it is much easier for a reviewer to read the program.
Methods may include local variables, which only exist as long as the method runs.
Local Variables are given a name and Quantity type.
When calling a method, local variables are automatically set to "invalid", and must be initialized by the program before they can be used. (Security) .
When a method performs a calculation, the outcome is influenced by the data instance values and their Data Quality indications, which will be included in the result of calculation. In other words, if one or more are marked invalid, the result will also be invalid.
Step 7: Repeating the regulation
You need to make sure that your regulation continuously run at specific intervals, and for this you use the timer subcomponent that you added earlier.
In the first line of the program it says INHERITED. This indicates that the method of the ancestor will be executed. Never delete the INHERITED, unless you specifically understand what you ancestor (and its ancestor-chain)
Now implement program code to:
Call the Regulate method
Run the Timer again in time defined by your constant Regulating_interval .
What your code should look like:
All devices include a TASK manager with a number of TASK components. The TASK manager allocates CPU time for the methods in the different components.
The TASK manager includes a stack for running the program. The stack size is the same for all TASK managers in a device. It will be adapted to the method in the device with the highest memory need.
The COPP system is designed for event-driven methods with short execution periods, and does not use a ’Change Task’, since this would require a stack for each method.
A Task Manager contains two queues.
The TASK manager's job is to take a vacant TASK and start to run the Timermethod in the first component in the timer queue at the specified time.
Otherwise the first component in the Async queue is run with the method specified in the chain.
To ensure that timer methods in the Timer queue do not occupy the CPU 100%, a method from the Timer queue is always followed by a method from the Async queue and vice versa. If the next specified time in the timer queue is later than current time, a Async queue method is executed instead.
Only methods without any parameters and results can be in the Async queue.
Only the Timermethod in timer subcomponents can be inserted in the timer queue.
A method can only be in a queue once.
When calling methods in remote components, the calling TASK is parked while waiting for response.
After a reset, the Init method of all components is called.
Step 8: Handling the startup (init).
You need to be sure that your system is in a well known state before you start your regulation.
What your code should look like:
In VIGO6 you decide at component level what parts of the component to make available for visualisation. Any data that you want the "outside world" to edit and/or see need to be put in a register (as we did for set point and actual temperature).
Let us make a simple view for our temperature regulator component.
Step 9: Create view for temperature regulator component.
Open your control component XX_Temperature_regulator_simple
Rename the view to "Window_for_XX-temperature_regulator_simple"
Save your view.
Right click on view list and select "add"- "view for control instance" Click on the plus sign beside " XX_temperature_regulator_simple". Select register "setpoint". Select view PD_2159 - Number_name_value_unit.
On your visualisation you now see the element and you can drag it to a suitable position on the screen.
Your visualisation should look something like this:
CONGRATULATIONS! You have now created your control component with control logic and visualisation and it can be reused over and over.
And to recap, here is what you have built: