How to change device setting by popup
(YouTube video link at the end)

 

This article includes a description how of motor setting parameters can be changed by using TwinCAT HMI. There might be many different types of settings depending on motor and manufacturer. We shall consider or show how to create a popup in TwinCAT HMI and how the data can be saved to PLC and read those back and display in the popup setting. Other settings may be added to the popup by following the same  process.

Download the content: MotorSetting_Hemelix.zip  

 

If we click on the motor symbol (in the HMI) then it will popup a dialog from where we can set the parameters. The parameters are saved to the PLC (see the persistence data setting article in the PLC section at  https://www.hemelix.com/automation/twincat-persistent-data/)

We shall discuss how the persistent data can be displayed in the popup, change it there and store it back to PLC. We are saving the data every 100 seconds interval. We need to save the data in a certain interval for avoiding losses of data.

Our settings are  like the following:

VAR PERSISTENT
	motorStartTime : INT;  //Seconds
	motorStopTime : INT;  //Seconds
motorRPM : REAL; //rpm END_VAR

 

We shall create a sample that can be used to load the settings (persistent data) to the HMI, if we edit the data then we can save those to the PLC.

DESIGN STEPS :

=> Start Visual Studio and create an empty HMI project

=> Create two folders (UserControl and JavaScript)

=> Create two user controls (motor.usercontrol for displaying the motor and SettingsPopup.usercontrol for displaying the settings as popup)

=> See this article about user control if not familiar.

Left side image is the motor user control and second side image is for the pop up where we can edit the settings and save it.

 

Add the following parameter name and datatype for motor user control

Add the following parameter name and datatype for popup settings user control

Now we have added the necessary parameters, let us start linking the PLC variable to the HMI variable. We have 3 parameters in the popup, these are Motor Start Time, Motor Stop Time, and Revolution per minute. Motor start time means here is that motor start delay and motor stop delay (the name is a bit misleading).  These parameters are stored in the persistent memory of the PLC. When we press on the Start/Stop button the motor will start after a delay and that is equal to the motor start time. In the same way, when the motor is running and if we press stop then the motor will stop after motor stop time seconds.

//PLC Program
//Header
FUNCTION_BLOCK MotorAC
VAR_INPUT
END_VAR
VAR_OUTPUT
END_VAR
VAR
motorName : STRING :='AC Motor';
maxRotationValue : REAL := 0.0;
rotationPerMinute : REAL := 0.0;
myTimerStart : TON ;
myTimerStop : TON ;
motorAlarm : BOOL := FALSE;
motorReset : BOOL := FALSE;
index : INT := 1;
initDone : BOOL := FALSE;

startMotor : BOOL := FALSE;
doMotorOutPut : BOOL := FALSE;
motorStarted : BOOL := FALSE;
END_VAR
VAR PERSISTENT
motorStartTime : REAL;  //Seconds
motorStopTime : REAL;  //Seconds
motorRPM : REAL; //rpm
END_VAR
//Body of the program
IF startMotor = TRUE AND motorStarted = FALSE THEN
myTimerStart(IN:= startMotor AND NOT motorStarted, PT:= REAL_TO_TIME(motorStartTime*1000.0));
END_IF 
IF NOT startMotor AND motorStarted THEN
myTimerStop(IN:= NOT startMotor AND motorStarted, PT:= REAL_TO_TIME(motorStopTime*1000.0));
END_IF
IF NOT initDone THEN
motorName := CONCAT(motorName, INT_TO_STRING(index)); //Should be done single time in a initialize
IF motorRPM = 0.0 THEN // reset all
motorRPM := 100.0;
motorStartTime := 5.0;
motorStopTime := 5.0;
END_IF
initDone := TRUE;
END_IF
IF  maxRotationValue > 100.0  OR maxRotationValue < 0.0 THEN
motorAlarm := TRUE;
ELSE
motorAlarm := FALSE;
END_IF
IF motorReset THEN
motorAlarm := FALSE;
startMotor := FALSE;
motorReset := FALSE;
END_IF
IF myTimerStart.Q AND NOT motorStarted AND startMotor THEN
doMotorOutPut:= TRUE;
motorStarted := TRUE;
myTimerStart(IN:= FALSE);
END_IF
IF myTimerStop.Q AND motorStarted THEN
startMotor := FALSE;
doMotorOutPut := FALSE;
motorStarted := FALSE;
myTimerStop(IN:= FALSE);
END_IF

When we press on the button (Start/Stop) then we write to the PLC variable startMotor by the following code. It toggle the startMotor variable in PLC.


var symbol = '%pp%motorStartStop%/pp%';
console.log(`startMachinePopup button pressed = ${symbol}`);
TcHmi.Symbol.readEx2( symbol, function (data2) {
    if (data2.error === TcHmi.Errors.NONE) {        
        var result = data2.value;
        if(result == false) {
            TcHmi.Symbol.writeEx(symbol, true, function (data3) {
            if (data3.error === TcHmi.Errors.NONE) {
                console.log('Write true OK to motorStartStop'); 
            } else {
                console.log('Write true NOK to motorStartStop'); 
            }
        });        
        } else {
            TcHmi.Symbol.writeEx(symbol, false, function (data4) {
            if (data4.error === TcHmi.Errors.NONE) {
                console.log('Write false OK to motorStartStop'); 
            } else {
                console.log('Write false NOK to motorStartStop'); 
            }    
         });    
        }            
    }   
});

When PLC see that startMotor variable is true then it sets the motorStarted to true after the settings value. So we monitor the motorStarted  variable in the PLC. If the variable is true then we start rotation and if the variable is false then we stop the rotation. The following JS code is used for this.  


//30 rpm == 33.33333 minutes == 2000 seconds to rotate 360000 dg
var timeS = 2000;
var motorStartedParam = '%pp%motorStarted%/pp%';   
var rpmMotor = '%pp%motorRPM%/pp%';   
 TcHmi.Symbol.readEx2(rpmMotor, function(data) {                                                if (data.error === TcHmi.Errors.NONE) {           var rpm = data.value;         console.log(rpm);         timeS = (2000 *30)/rpm;     }                              }); 
 TcHmi.Symbol.readEx2(motorStartedParam, function(data) {                                                   if (data.error === TcHmi.Errors.NONE) {                                                       if(data.value == true) {                                         var angle = 360000
    console.log('motorStarted TRUE');     var finalFrame = 'rotate('.concat(angle.toString()).concat('deg)');
        animationGlobal = new TcHmi.Animation('TcHmi_Controls_Beckhoff_TcHmiImage_MotorRotationImage', '');         animationGlobal.addKeyframe('transform', 'rotate(0deg)', 0)     .addKeyframe('transform', finalFrame, 1)     .duration(timeS*1000);       animationGlobal.run();                                           }                                 
else  {     console.log('Reset');
//Stop the animation and put back the beckhoff image to horizontal position
//I don't have reference to the animation object if I don't declare in code behind file or in some otherway
//At least if I declare the animation in a code behind  file  then I have access to the object and I can reset it or pause it
//Problem with pause the image does not go to the original shape  
//Problem with reset, the animation does not start again if I create the animation in code behind file. If I declare it in code behind file and 
//initialized in the embedded code then it is  fine.  But I am not sure related to memory leak or other performence issue.
//With subscription, I have similar issues.
//animationGlobal.pause(); animationGlobal.reset(); } }                                                                               }); 

 

 

 

We shall add a Youtube Video here! Download the sample from the link given above.

 

Download the sample from the link given above.

 

Next, let’s try to understand what is a view at https://www.hemelix.com/scada-hmi/beckhoff-hmi/checkboxcombobox/

 

Ask questions related to Hemelix sample code and design at Google group https://groups.google.com/g/hemelix