Rotating an Image around center by animation framework

The TwinCAT HMI framework can be used to rotate an image easily. But if you want to do it in a certain way (depending on the complexity) it may be difficult. We want to rotate an image around the center based on a variable in PLC. If the PLC variable is TRUE then we start a rotation if it is FALSE we stop the rotation. This can be useful for example in relation to a motor. We want to display how a motor is running at a certain speed.

I have tried to use the transformation function with a timer but it is not smooth. So animation framework help to display the rotation smoothly. We shall design the sample to display the DC motor speed in our fictitious home automation system.

Animation_Rotation_BeckhoffImage.zip

A keyframe (or keyframe) in animation and filmmaking is a drawing or shot that defines the starting and ending points of any smooth transition. TwinCAT HMI allows us to create and configure animations that can be played using CSS or JavaScript. The Animation API is designed for use within controls.

HMI and the PLC program

Figure 1: Main view of the  sample application, relation between PLC, angle of rotation and time

The main user interface and a tiny PLC program are in the background. The simple PLC program has a variable called start rotation. If this variable is TRUE then we rotate the Beckhoff image and stop the rotation (and set it to the original position). We need to set the variable to TRUE, since we don’t have any actual device, we set it by the button START/STOP.  The same button will toggle the start rotation variable. Try to download the sample and test it in your environment. 

Create the short PLC program and run it in Visual Studio. Make sure you can change the variable in the PLC program. The HMI will monitor the startRotation variable, if the variable is true then the image will start rotating. When the value is false then it will stop.

//PLC Program
PROGRAM MAIN
VAR
startRotation : BOOL := FALSE;
END_VAR

Figure 2: Very simple PLC program for indicating the image rotation or stop condition

 If you are new and have not started yet, please  take a look at this sample first https://www.hemelix.com/scada-hmi/twincat-hmi/twincat-hmi-installation/

Design of the sample:

 

STEP 01:

=>Create an HMI project by visual studio

=>insert the following control from the tool box (View | ToolBox or CTRL+ALT+X )

Text block: Change the text to Angle 

Chage the ID to TcHmi_Controls_Beckhoff_TcHmiTextbox_Angle

Text box: Change the text to 36000

Text block: Change the text to Time

Chage the ID to TcHmi_Controls_Beckhoff_TcHmiTextbox_Time

Text box: Change the text to 2000

Start/Stop button: for changing the PLC variable

Now the HMI content is ready, but it just display the content if you run. We need to link the HMI to PLC program.

STEP 02:

=> Make sure that the PLC variable is available in the HMI (Select TwinCAT Project | TwinCAT HMI | TwinCAT HMI Server configuration)

=> ADS | RunTimes | PLC1 | Accept (as shown in the following image)

 

Figure 3: PLC and the HMI linking process, we need to tell HMI from which PLC the data should be read

STEP 03 :

=> Configure Start/Stop button so when we press it will toggle the startRotation in PLC

=>Create a folder in the HMI project, name it JavaScript and insert a code behind file (if needed see https://www.hemelix.com/scada-hmi/twincat-hmi/twincat-javascript-function-and-code-behind/)

=> Declare a animation object there

module TcHmi {
    // If you want to unregister an event outside the event code you need to use the return value of the method register()
    var destroyOnInitialized = TcHmi.EventProvider.register('onInitialized', function (e, data) {
        // This event will be raised only once, so we can free resources. 
        // It's best practice to use destroy function of the event object within the callback function to avoid conflicts.
        e.destroy();
        // ----------------------
        // Place your code here!
        // ----------------------
        var animationGlobal; //<<<< This the variable we are talking about
    });
}

Figure 4: HMI code behind file for holding global variable

STEP 04:

=> Select the Beckhoff image and bring the properties (select the range tool or F4 )

=> Press on the event button (lightning bolt)

=>Configure the Custom event to tell framework to do some action when the startRotation in the PLC changes as shown in the following image.

 

Figure 5: Actual animation done by this JavaScript code

=> 1 => Bring the events  view

=> 2 => Monitor the PLC variable as custom events

=> 3 => Configure the actions

=> 4 => Bring the JavaScript editor by drag and drop (JavaScript item from the left pane)

=> 5 => Bring the JavaScript editor window

=> 6 => Paste the actual JavaScript code!

We need to insert the java script code. See how we are reacting to the changes of variable. Once you have inserted the script you are ready to test it.

 

var startMotor = '%s%PLC1.MAIN.startRotation%/s%';
TcHmi.Symbol.readEx2(startMotor,
function(data) {
  if (data.error === TcHmi.Errors.NONE) {
    if (data.value == true) {
      var angleControl = TcHmi.Controls.get("TcHmi_Controls_Beckhoff_TcHmiTextbox_Angle");
      var timeSControl = TcHmi.Controls.get("TcHmi_Controls_Beckhoff_TcHmiTextbox_Time");
      if (angleControl != undefined && timeSControl != undefined) {
        var angle = parseFloat(angleControl.getText(), 10);
        var timeS = parseFloat(timeSControl.getText(), 10);
        var finalFrame = 'rotate('.concat(angle.toString()).concat('deg)');
        console.log(finalFrame);
        console.log(timeS);
        animationGlobal = new TcHmi.Animation('ViewDesktopBeckhoffLogo', '');
        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 deslare 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();
    }
  }
});
 

Figure 6: JavaScript code that is used in the action, ready for copy, if you have not downloaded it

=> Test it  and see the result.

I have a question to you for discussion in https://groups.google.com/g/hemelix, since animation framework takes time value when we create or configure the animation object, what value we should set and how? Lets discuss in the group.

Download the sample:

Link is given at the top

 

How to rotate Image in generic way

We can create a JavaScript function and pass parameter and image id. Also, we can pass the amount of time and speed information there. Whenever we need to rotate, this will create smooth animation.

Reference:

 

 https://infosys.beckhoff.com/english.php?content=../content/1033/te2000_tc3_hmi_engineering/36028800864323851.html&id=

https://developer.mozilla.org/en-US/docs/Web/CSS/animation

 

Download the sample from the link given above.

 

Next, let’s try to display data as a tree by JavaScript at https://www.hemelix.com/scada-hmi/twincat-hmi/display-tree-like-nodes-to-twincat/

 

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