<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>TwinCAT Archives | DMC, Inc.</title>
	<atom:link href="https://static.dmcinfo.com/blog/tag/twincat/feed/index.xml" rel="self" type="application/rss+xml" />
	<link></link>
	<description></description>
	<lastBuildDate>Fri, 04 Sep 2026 15:47:54 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.2</generator>

<image>
	<url>https://static.dmcinfo.com/wp-content/uploads/2025/04/site-icon-150x150.png</url>
	<title>TwinCAT Archives | DMC, Inc.</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Guide to Beckhoff Safety PLC Communication over EtherCAT Network (FSoE Over EAP)</title>
		<link>https://static.dmcinfo.com/blog/16745/guide-to-beckhoff-safety-plc-communication-over-ethercat-network-fsoe-over-eap/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Wed, 17 Jan 2024 20:09:01 +0000</pubDate>
				<category><![CDATA[Beckhoff PLC]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[PLC]]></category>
		<category><![CDATA[EAP]]></category>
		<category><![CDATA[PLC Communication]]></category>
		<category><![CDATA[Safety PLC]]></category>
		<category><![CDATA[TwinCAT]]></category>
		<category><![CDATA[TwinSAFE]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/16745/guide-to-beckhoff-safety-plc-communication-over-ethercat-network-fsoe-over-eap/</guid>

					<description><![CDATA[<p>Communication between Safety PLCs is a useful tool for complicated projects involving multiple Safety PLCs: such as&#160;projects requiring Estops to cut power to multiple machines. This guide will explain how to set up safety communication for Beckhoff Safety PLCs while focusing on a setup with 1-1 communication between two&#160;PLCs using UDP/IP. Table of Contents System [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/16745/guide-to-beckhoff-safety-plc-communication-over-ethercat-network-fsoe-over-eap/">Guide to Beckhoff Safety PLC Communication over EtherCAT Network (FSoE Over EAP)</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Communication between Safety PLCs is a useful tool for complicated projects involving multiple Safety PLCs: such as&nbsp;projects requiring Estops to cut power to multiple machines.</p>



<p class="wp-block-paragraph">This guide will explain how to set up safety communication for Beckhoff Safety PLCs while focusing on a setup with 1-1 communication between two&nbsp;PLCs using UDP/IP.</p>



<h2 id="h-table-of-contents" class="wp-block-heading"><a id="Table of Contents" name="Table of Contents">Table of Contents</a></h2>



<ol class="wp-block-list">
<li><a href="#System Overview">System Overview</a></li>



<li><a href="#Hardware and IPC Settings">Hardware and IPC Settings</a></li>



<li><a href="#IO Tree">IO Tree</a></li>



<li><a href="#Developing the Safety Program">Developing the Safety Program</a>
 
 
<ol class="wp-block-list" start="1" style="list-style-type: lower-alpha;">
  

<li><a href="#Creating the Custom FSoE Connection">Creating the Custom FSoE Connection</a></li>


  

<li><a href="#Adding and Linking Safety Variables">Adding and Linking Safety Variables</a></li>


 </ol>
</li>
</ol>



<h2 id="h-system-overview" class="wp-block-heading"><a id="System Overview" name="System Overview">System Overview</a></h2>



<p class="wp-block-paragraph"><em><a href="#Table of Contents">Back to Table of Contents</a></em></p>



<p class="wp-block-paragraph">The FSoE over EAP network is used when Safety PLCs are connected by ethernet but do not share an EtherCAT Master&nbsp;as they are not in the same TwinCAT solution. An EtherCAT Automation Protocol (EAP)&nbsp;connection is needed between the two PLCs to make communication possible.</p>



<p class="wp-block-paragraph">The EAP network will consist of one Publisher and one Subscriber on each PLC. The Publisher will host a Safety network variable that will be linked to a Custom FSoE Connection in its safety program, which the other PLC&#8217;s Subscriber will link to a custom FSoE Connection in its safety program. This will allow for two-way communication between the two&nbsp;PLCs over ethernet.</p>



<p class="wp-block-paragraph">The network is configured so that one safety PLC is assigned as the EtherCAT Master, and the other as the EtherCAT Slave. The Master and Slave have their own set of EAP Publishers, EAP Subscribers, and different settings inside the safety program.</p>



<h4 id="h-note-if-using-project-variants" class="wp-block-heading">Note If Using Project Variants</h4>



<p class="wp-block-paragraph">If you use the same TwinCAT solution for both Safety PLCs using project variants, I recommend creating two&nbsp;Safety Programs, and two EtherCAT Masters for the Safety PLCs: one&nbsp;for the EtherCAT Master&nbsp;and one&nbsp;for the EtherCAT Slave.</p>



<p class="wp-block-paragraph">The project variants can be used to selectively disable the unused project and IO devices. This is the recommended protocol due to differences in the safety project and device linking that are not changed automatically by project variants or by changing the target PLC.</p>



<p class="wp-block-paragraph">Example:</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/device-menu_1.png" alt=""/></figure>



<h2 id="h-hardware-and-ipc-settings" class="wp-block-heading"><a id="Hardware and IPC Settings" name="Hardware and IPC Settings">Hardware and IPC Settings</a></h2>



<p class="wp-block-paragraph"><em><a href="#Table of Contents">Back to Table of Contents</a></em></p>



<p class="wp-block-paragraph">To set up the EAP network, a few things must be configured on the PLC’s IPC and on the physical device:</p>



<ol class="wp-block-list">
<li>For a network of only EL 6900s, they <strong>must</strong> have different Safe Addresses. Adjust the DIP switches as needed.

 
 
<ol class="wp-block-list" style="list-style-type:lower-alpha;">
  

<li>A network including newer Safety PLCs such as the EL 6910 do not need unique Safe Addresses;&nbsp;however, they are still recommended to avoid confusion when downloading the safety projects.</li>


 </ol>
</li>



<li>If you plan to use UDP/IP communication, add Firewall rules to allow EAP port&nbsp;34980 / udp (incoming) on the PLCs.</li>



<li>Add a static route between the PLCs.</li>
</ol>



<h2 id="h-io-tree" class="wp-block-heading"><a name="IO Tree">IO Tree</a></h2>



<p class="wp-block-paragraph"><em><a href="#Table of Contents">Back to Table of Contents</a></em></p>



<p class="wp-block-paragraph">To begin, the EAP network device must be added to both TwinCAT projects inside the IO Tree.</p>



<p class="wp-block-paragraph">DMC engineer&nbsp;<a href="https://static.dmcinfo.com/about/employee-bios/casey-langenbahn">Casey Langenbahn</a> has written a separate <a href="https://static.dmcinfo.com/latest-thinking/blog/id/10419/categoryid/10/beckhoff-plc-to-plc-communication-using-eap--a-starter-guide">guide for setting up EAP</a> that may be helpful.</p>



<ol class="wp-block-list">
<li>In the IO tree, add a new device: <em>EtherCAT Automation Protocol (Network Variables)</em><br>
 <br>
 


<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/io-menu-add-new-item_1.png" alt=""/></figure>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/insert-device-window_1.png" alt=""/></figure>
</li>



<li>In the settings of the EAP device, select the “Adapter” tab. Then, click “Search…” and select the Network Adapter with the ethernet connection to the other PLC.<br>
 
<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/device-found-at-window_1.png" alt=""/></figure>
</li>



<li>Within the EAP device, add a Subscriber and Publisher. While standard EAP communication can be one-way, a two-way connection between both is needed for Safety PLC communication.
 
 
<ol class="wp-block-list" style="list-style-type:lower-alpha;">
  

<li>If you are using project variants, both pairs of Subscriber/Publishers can be created within the same EAP device, with one set disabled automatically.<br />
  

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/device-menu-2_1.png"  /></figure>

</li>


  

<li>Double click the Publisher device and go to the Publish tab.</li>


  

<li>Set the Publisher settings to UDP/IP,&nbsp;select Unicast, and set the IP address and gateway of the paired PLC.&nbsp;
  

<ol class="wp-block-list" start="1" style="list-style-type: lower-roman;">
   

<li>Unicast is used for 1-1 communication with a PLC. This setting will need to be changed if you are connecting multiple PLCs to each other.</li>


   

<li>For example, a setup with the following:
   

<ol class="wp-block-list" start="1" style="list-style-type: upper-alpha;">
    

<li>Master with IP Address: 10.16.8.103</li>


    

<li>Slave with IP Address: 10.16.8.104</li>


   </ol>


   </li>


   

<li>For the Master&rsquo;s Publisher:<br />
   

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/master-pubilsher-settings_1.png"  /></figure>

</li>


   

<li>For Slave&rsquo;s Publisher:<br />
   

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/slave-publisher-settings_1.png"  /></figure>

</li>


  </ol>


  </li>


  

<li>Set Subscriber settings to the matching PLC&apos;s net ID.
  

<ol class="wp-block-list" start="1" style="list-style-type: lower-roman;">
   

<li>For Master&rsquo;s Subscriber:<br />
   

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/master-subscriber-settings_1.png"  /></figure>

</li>


   

<li>For Slave&rsquo;s Subscriber:<br />
   

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/slave-subscriber-settings.png"  /></figure>

</li>


  </ol>


  </li>


 </ol>
</li>



<li>Note: Using RT-ethernet is possible instead of UDP/IP. If desired, adjust the settings above to the correct AMS NetIds. Ensure that the NetId within the EAP device is set correctly.</li>



<li>Next, add safety network variables to the Publisher and Subscriber for our safety communication. Each network variable will be connected to a custom FSoE Connection Alias device.
 
 
<ol class="wp-block-list" style="list-style-type:lower-alpha;">
  

<li>If the network has only EL6900s, then the network is limited to only one&nbsp;Custom FSoE Connection, so only one&nbsp;network variable is allowed.</li>


  

<li>If the network has at least one&nbsp;EL6910 or newer, then multiple connections are allowed. Create a network variable for each safety group in the safety program.</li>


 </ol>
</li>



<li>Right click the Publisher and&nbsp;click “Add new item.”<br>
 
 
 


<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/insert-network-variable-window.png" alt=""/></figure>



<ol class="wp-block-list" start="1" style="list-style-type: lower-alpha;">
  

<li>Set the name of the datatype.</li>


  

<li>Set the ID to a unique number.</li>


  

<li>Select the data type. The EAP protocol allows for many types of data to be communicated, but, for safety communication, choose one of the available FSoE_X Safety data.
  

<ol class="wp-block-list" start="1" style="list-style-type: lower-roman;">
   

<li>The X signifies the size of the data type, with larger sizes allowing for more data to be communicated.</li>


   

<li>There is some overhead within the data packet, so the number of usable bytes is:
   

<ul class="wp-block-list">
    

<li>FSoE_6: 1 byte of safety variables (8 bits)</li>


    

<li>FSoE_7: 2 bytes (16 bits)</li>


    

<li>FSoE_11: 4 bytes</li>


    

<li>FSoE_15: 6 bytes</li>


   </ul>


   </li>


  </ol>


  </li>


 </ol>
</li>



<li>Then in the Subscriber, add the data types that will be in the Publisher of the matching PLC.
 
 
<ol class="wp-block-list" style="list-style-type:lower-alpha;">
  

<li>For example, if PLC 1&rsquo;s Publisher has data type PLC_1_data and PLC 2&rsquo;s Publisher has PLC_2_data, set PLC 1&rsquo;s Subscriber to PLC_2_data, and PLC 2&rsquo;s Subscriber to PLC_1_data.</li>


  

<li>If the matching PLC is already running the program with the EAP variables, then clicking the &ldquo;Browse for Computer&rdquo; button and selecting the matching PLC can be used to try to add the variables automatically.</li>


  

<li>Otherwise, new variables can be added by clicking &ldquo;Create new Variable&hellip;&rdquo;<br />
  

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/import-network-variable-window.png"  /></figure>

</li>


  

<li>Set up the device so it will match the Publisher of the other Safety PLC&rsquo;s data.
  

<ol class="wp-block-list" start="1" style="list-style-type: lower-roman;">
   

<li>Make sure to set the Variable ID correctly.<br />
   

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/insert-network-variable-window-2.png"  /></figure>

</li>


  </ol>


  </li>


 </ol>
</li>



<li value="NaN">Repeat Steps 4 and 5 for the other PLC, creating the FSoE Safety data within the Publisher and Subscriber.</li>
</ol>



<h2 id="h-developing-the-safety-program" class="wp-block-heading"><a id="Developing the Safety Program" name="Developing the Safety Program">Developing the Safety Program</a></h2>



<p class="wp-block-paragraph"><em><a href="#Table of Contents">Back to Table of Contents</a></em></p>



<h3 id="h-creating-the-custom-fsoe-connection" class="wp-block-heading"><a id="Creating the Custom FSoE Connection" name="Creating the Custom FSoE Connection">Creating the Custom FSoE Connection</a></h3>



<p class="wp-block-paragraph"><em><a href="#Table of Contents">Back to Table of Contents</a></em></p>



<p class="wp-block-paragraph">This guide will assume that the safety program includes multiple safety groups that require safety communication.</p>



<ol class="wp-block-list">
<li>If the network only has EL6900s, then the network is limited to only 1 Custom FSoE Connection, so it is recommended that safety communication is added to a separate safety group.
 
 
<ul class="wp-block-list">
<li>If it is not in a separate safety group, it becomes possible that an issue within a single safety group will cause all safety communication to fail, bringing all safety groups down.</li>



<li>Ex:<br>
  
<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/safety-group-menu.png" alt=""/></figure>
</li>
</ul>
</li>



<li>If the network has at least 1 EL6910 or newer, then multiple connections are allowed. Create one&nbsp;network variable for each safety group in the safety program.<br>
 
<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/safety-group-menu-2.png" alt=""/></figure>
</li>



<li value="NaN">Create an Alias device in the safety group. Right click &ldquo;Alias Devices&rdquo; and select &ldquo;Add new Item.&rdquo;&nbsp;In the popup that appears, select Safety &gt;&nbsp;EtherCAT and choose &quot;Custom FSoE Connection.&quot;<br />
 

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/add-new-item-window-safety-project-1-slave.png"  /></figure>

</li>



<li>In the Alias device created, set the Safe Address of the Custom FSoE Connection.
 
 
<ol class="wp-block-list" start="1" style="list-style-type: lower-alpha;">
  

<li>If the Safety PLCs are both EL6900s, set the Safe Address to the matching PLC&rsquo;s Dip Switch Safe Address.<br />
  

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/linking-tab-safe-addresses.png"  /></figure>


  

<ol class="wp-block-list" start="1" style="list-style-type: lower-roman;">
   

<li>Ex: If PLC 1&rsquo;s dip switch Safe Address is 1, set PLC 2&rsquo;s custom FSoE connection to 1 and vice versa.</li>


  </ol>


  </li>


  

<li>If one of the Safety PLCs is an EL6910 or newer, the Safe Address can be set to any unique number. Set both PLCs to the same number.</li>


  

<li>See the graph below for more information:<br />
  

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/master-and-slave-device-details.png"  /></figure>

</li>


 </ol>
</li>



<li>In the Connection tab, set the Mode to either EtherCat Master or Slave (the matching PLC will have the opposite).
 
 
<ol class="wp-block-list" style="list-style-type:lower-alpha;">
  

<li>Note: if the one of the safety PLCs is an EL6900, it must be set to the FSoE Master. If not, the unique Safe Address set in the previous step will fail.</li>


 </ol>
</li>



<li>Set the Type to the correct Safety PLC card.<br>
 
<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/connection-tab-settings.png" alt=""/></figure>
</li>



<li value="NaN">In the Process Image tab, set the number of bytes of the alias device to match the FSoE network variable in the EAP Publisher and Subscriber.<br />
 

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/process-image-tab.png"  /></figure>


 

<ol class="wp-block-list" start="1" style="list-style-type: lower-roman;">
  

<li>Ex: If you are using FSoE_6, set it to 6 bytes; if FSoE_7, then set it to 7 bytes, etc.</li>


  

<li>This guide assumes that both PLC&apos;s Publisher data is the same data type. However, the Process Image data type sizes can be adjusted as needed.</li>


 </ol>


 </li>



<li value="NaN">Next, link the alias device&rsquo;s input to the correct variable in the EAP Publisher.
 

<ol class="wp-block-list" start="1" style="list-style-type: lower-alpha;">
  

<li>Click the link variable button next to the Input section highlighted in red.</li>


  

<li>In the popup that appears, Unselect &ldquo;Exclude Other Devices.&rdquo;</li>


  

<li>Select the &ldquo;Exclude Disabled,&rdquo;&nbsp;&ldquo;Matching Type,&rdquo;&nbsp;and &ldquo;Matching Size&rdquo; checkboxes to assist in finding the correct variable.
  

<ol class="wp-block-list" start="1" style="list-style-type: lower-roman;">
   

<li>If using project variants, ensure the correct set of Publisher/Subscriber is disabled.</li>


  </ol>


  </li>


  

<li>If the EAP device does not appear, double check that the data type matches the Publisher/Subscriber&rsquo;s data type.<br />
  

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/linking-tab-safe-addresses-2.png"  /></figure>

<br />
  

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/attach-variable-message-window.png"  /></figure>

</li>


 </ol>


 </li>



<li value="NaN">Similarly, connect the output to the Subscriber&rsquo;s network variable.

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/linking-tab-safe-addresses-3.png"  /></figure>


<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/attach-variable-message-window-2_1.png"  /></figure>

</li>



<li value="NaN">Repeat step 3 for the other PLC and connect the EAP device to the custom FSoE Connection. Make sure that the EtherCAT Master/Slave setting is correct.</li>
</ol>



<h3 id="h-adding-and-linking-safety-variables" class="wp-block-heading"><a name="Adding and Linking Safety Variables">Adding and Linking Safety Variables</a></h3>



<p class="wp-block-paragraph"><em><a href="#Table of Contents">Back to Table of Contents</a></em></p>



<h3 id="h-el6900s-only-and-multiple-safety-groups" class="wp-block-heading">EL6900s Only and Multiple Safety Groups:</h3>



<p class="wp-block-paragraph">For a setup with only EL6900s and multiple safety groups in the program, the alias device must be added to only 1 Safety Group, and then, the data must be decoupled to pass to other safety groups. To accomplish this:</p>



<ol class="wp-block-list">
<li>Inside the safety group that has the custom FSoE Connection, create two&nbsp;safeDecouple FBs and add safety variables for all inputs and outputs for the communication.
 
 
<ol class="wp-block-list" style="list-style-type:lower-alpha;">
  

<li>One safeDecouple will be for inputs from the custom connection, the other for outputs to the custom connection.<br />
  

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/safety-group-1.png"  /></figure>

</li>


 </ol>
</li>



<li>Then, assign the input and output variables to the correct bit inside the safety alias device.
 
 
<ol class="wp-block-list" style="list-style-type:lower-alpha;">
  

<li>For an input into the safety program:<br />
  

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Picture25.jpg"  /></figure>

<br />
  

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/map-local-variable-window.png"  /></figure>

</li>


 </ol>
</li>



<li value="NaN">Open the safety group where the safety input will be used and link the FB input to the Decouple Output under the Safety Communication group.<br />
 

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/safe-estop.png"  /></figure>

<br />
 

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/map-function-block-port.png"  /></figure>

</li>



<li value="NaN">If there are variables that will be passed from this safety group to the other safety PLC, add a safeDecouple FB. Connect the variables that will be communicated to the other PLC to the decouple&rsquo;s inputs.</li>



<li value="NaN">Then, link the output to the decouple in the SafetyCommunication group.<br />
 

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/safe-decouple.png"  /></figure>

<br />
 

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/map-function-block-port-2_1.png"  /></figure>

</li>



<li value="NaN">The result should look like this:
 

<ol class="wp-block-list" start="1" style="list-style-type: lower-alpha;">
  

<li>SafetyGroup1:<br />
  

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/safety-group-1-safeestop-and-safedecouple.png"  /></figure>

</li>


  

<li>Safety Communication Group:<br />
  

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/safe-decouple-2.png"  /></figure>

<br />
  

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/variable-mapping.png"  /></figure>

</li>


 </ol>


 </li>



<li>Repeat all steps for the other PLC&#8217;s data.</li>
</ol>



<h3 id="h-el6910s-and-newer-or-1-safety-group" class="wp-block-heading">EL6910s and Newer or 1 Safety Group:</h3>



<p class="wp-block-paragraph">A network with an EL6910 or newer, or only 1 safety group, is not limited to a single custom FSoE Connection; therefore, instead of creating a single Custom FSoE Connection and creating an additional Safety Group for communication, the custom connection can be created inside the safety group it will be used in.</p>



<ol class="wp-block-list">
<li value="NaN">Since each safety group can have its own Custom FSoE Connection, no safeDecoupling is required to transfer data between safety groups.</li>



<li value="NaN">The safety variables are created within the group and linked to the Custom FSoE Connection directly.<br />
 

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/final-result.png"  /></figure>

</li>



<li>Repeat with the other PLC.</li>
</ol>



<p class="wp-block-paragraph">With the IO, hardware, and software correctly setup, the EAP Network should begin communicating once the projects are downloaded to the PLCs, and everything is complete.</p>



<p class="wp-block-paragraph">I would like to thank Charles Zmuda from Beckhoff for his support in making this blog.</p>



<div class="wp-block-group alignwide has-custom-light-blue-background-color has-background is-layout-flow wp-container-core-group-is-layout-dbd34961 wp-block-group-is-layout-flow" style="border-radius:20px;margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50);padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-columns alignwide are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-43efaee5 wp-block-columns-is-layout-flex" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<h3 class="wp-block-heading has-text-align-left" id="h-have-an-upcoming-project-dmc-can-help-you-take-the-next-step"><strong>Enable Safety-Rated Communication Between Beckhoff PLCs</strong>.</h3>



<p class="has-text-align-left wp-block-paragraph" id="h-need-help-turning-ideas-into-outcomes-automation-project-to-the-next-level-contact-us-today-to-learn-more-about-our-solutions-and-how-we-can-help-you-achieve-your-goals">Explore our <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/" data-type="page" data-id="420">Automation</a> expertise in configuring TwinSAFE, FSoE, and EAP for reliable safety communication as well as our capabilities in <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/plc-programming/beckhoff-and-twincat-3-programming/" data-type="page" data-id="457">Beckhoff &amp; TwinCAT 3</a> Programming.</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<div class="wp-block-buttons is-horizontal is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-2236275c wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-base-contrast-color has-text-color has-link-color wp-element-button" href="https://static.dmcinfo.com/contact/">Contact Us</a></div>
</div>
</div>
</div>
</div>
<p>The post <a href="https://static.dmcinfo.com/blog/16745/guide-to-beckhoff-safety-plc-communication-over-ethercat-network-fsoe-over-eap/">Guide to Beckhoff Safety PLC Communication over EtherCAT Network (FSoE Over EAP)</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Beckhoff OOP: Part One &#8211; Methods and Properties</title>
		<link>https://static.dmcinfo.com/blog/17364/beckhoff-oop-part-one-methods-and-properties/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Sun, 23 Jul 2023 21:36:25 +0000</pubDate>
				<category><![CDATA[Beckhoff PLC]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[PLC]]></category>
		<category><![CDATA[Beckhoff]]></category>
		<category><![CDATA[Methods]]></category>
		<category><![CDATA[Object-Oriented]]></category>
		<category><![CDATA[OOP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Properties]]></category>
		<category><![CDATA[TwinCAT]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/17364/beckhoff-oop-part-one-methods-and-properties/</guid>

					<description><![CDATA[<p>Welcome to the first blog in this&#160;series on Beckhoff Object-Oriented Programming (OOP). OOP&#160;enables code to be divided into self-contained, reusable objects, resulting in code that is easier to understand, maintain, and update. Throughout this series, the reasons behind this advantage will hopefully become evident and clear. Beckhoff has a set of&#160;examples that will occasionally be [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/17364/beckhoff-oop-part-one-methods-and-properties/">Beckhoff OOP: Part One &#8211; Methods and Properties</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Welcome to the first blog in this&nbsp;series on Beckhoff Object-Oriented Programming (OOP).</p>



<p class="wp-block-paragraph">OOP&nbsp;enables code to be divided into self-contained, reusable objects, resulting in code that is easier to understand, maintain, and update. Throughout this series, the reasons behind this advantage will hopefully become evident and clear.</p>



<p class="wp-block-paragraph">Beckhoff has a set of&nbsp;<a href="https://infosys.beckhoff.com/content/1033/tc3_plc_intro/7623882635.html?id=4094185901331026706" target="_blank" rel="noreferrer noopener">examples</a> that will occasionally be referenced throughout this series.</p>



<p class="wp-block-paragraph">Object oriented programming exists of 4 pillars:</p>



<ol class="wp-block-list">
<li><strong>Encapsulation</strong>: Encapsulation refers to the grouping of data (variables, properties) and functions (methods, function blocks) into a single unit called an object. The single object allows for the internal code to be hidden from the application code.</li>



<li><strong>Inheritance</strong>: Inheritance allows objects to inherit properties and functions from other objects. This allows for code to be reused even if the logic is not exactly the same.</li>



<li><strong>Polymorphism</strong>: Polymorphism means the ability of objects to take on different forms or exhibit different behaviors based on the context. This is useful for devices that have very similar functions, but the processes for how they are completed are very different. </li>



<li><strong>Abstraction</strong>: Abstraction involves simplifying complex systems by breaking them down into more manageable and understandable parts. It focuses on only the essential properties and behaviors of an object while hiding the unnecessary details. </li>
</ol>



<p class="wp-block-paragraph">Beckhoff provides several different tools that can be used to achieve these four pillars. Throughout this series, it will be pointed out how each tool correlates to the four pillars.</p>



<p class="wp-block-paragraph">This first blog will touch on two basic principles of OOP, methods and properties.</p>



<h2 class="wp-block-heading" id="h-methods">Methods</h2>



<p class="wp-block-paragraph"><a href="https://infosys.beckhoff.com/content/1033/tc3_plc_intro/2530307467.html?id=770088965081884469" target="_blank">Methods</a>&nbsp;are&nbsp;actions that an object can perform, while <em>encapsulating </em>the details of how an object performs its tasks. Methods specify the behavior or actions that objects can perform, <em>abstracting </em>the implementation details and providing a clean interface for interacting with objects.</p>



<p class="wp-block-paragraph">Methods can perform operations, manipulate data, and they may or may not return a value depending on their implementation. As for what a method should return, this depends largely on whether the method will be completed in one scan or not. For example, commanding a conveyor to move 10 feet will take more than one scan. However, determining the value of a sensor only takes one scan.</p>



<p class="wp-block-paragraph">In addition, there are different access modifiers for methods, with the two main ones being <strong><code>PUBLIC</code></strong> and <strong><code>PRIVATE</code></strong>. Public versus private determines whether the method can be called outside of the program or function block.&nbsp;There are two additional modifiers:&nbsp;<strong><code>PROTECTED</code></strong>, which allows any function block that inherits the function block&nbsp;to access the method&nbsp;(more on that in future blogs) and <strong><code>INTERNAL</code></strong>, which restricts access to objects in the library.</p>



<p class="wp-block-paragraph">In the example of commanding a conveyor to move 10 feet, the method may return a standard response that can be used in&nbsp;an application. This should be public because function blocks outside of the conveyor will need to call this.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
TYPE ST_Response 
STRUCT
    bComplete : BOOL;
    bError : BOOL;
END_STRUCT
END_TYPE
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #569CD6">TYPE</span><span style="color: #D4D4D4"> ST_Response </span></span>
<span class="line"><span style="color: #D4D4D4">STRUCT</span></span>
<span class="line"><span style="color: #D4D4D4">    bComplete : BOOL;</span></span>
<span class="line"><span style="color: #D4D4D4">    bError : BOOL;</span></span>
<span class="line"><span style="color: #D4D4D4">END_STRUCT</span></span>
<span class="line"><span style="color: #D4D4D4">END_TYPE</span></span>
<span class="line"></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
METHOD PUBLIC MoveDistance : ST_Response
VAR_INPUT
    Distance : LREAL; // feet 
END_VAR
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #569CD6">METHOD</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">PUBLIC</span><span style="color: #D4D4D4"> MoveDistance : ST_Response</span></span>
<span class="line"><span style="color: #D4D4D4">VAR_INPUT</span></span>
<span class="line"><span style="color: #D4D4D4">    Distance : LREAL; </span><span style="color: #6A9955">// feet </span></span>
<span class="line"><span style="color: #D4D4D4">END_VAR</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">When the method has completed, the state machine can then be moved to the next step. If it encounters an error during the process, the application can enter its error handling sequence.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
E_State.MOVE_CONVEYOR:
    respone := fbConveyor.MoveDistance(10); // move 10 feet
    
    IF respone.bComplete THEN
        eState := E_State.RUN_MACHINE;
    ELSIF respone.bError THEN
        eState := E_State.ERROR;
    END_IF
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #D4D4D4">E_State.MOVE_CONVEYOR:</span></span>
<span class="line"><span style="color: #D4D4D4">    respone := fbConveyor.MoveDistance(</span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4">); </span><span style="color: #6A9955">// move 10 feet</span></span>
<span class="line"><span style="color: #D4D4D4">    </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">IF</span><span style="color: #D4D4D4"> respone.bComplete </span><span style="color: #569CD6">THEN</span></span>
<span class="line"><span style="color: #D4D4D4">        eState := E_State.RUN_MACHINE;</span></span>
<span class="line"><span style="color: #D4D4D4">    ELSIF respone.bError </span><span style="color: #569CD6">THEN</span></span>
<span class="line"><span style="color: #D4D4D4">        eState := E_State.ERROR;</span></span>
<span class="line"><span style="color: #D4D4D4">    END_IF</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">An example of a method that takes one scan is&nbsp;calculating the torque of the conveyor. For calculating torque, it is often useful to implement a moving average or filter to smooth out any noise in the data. For example, a&nbsp;method can do all of the math inside and return the value in terms of foot-pounds. This would be an example of a private method because only the conveyor function block should be calling this. The torque could be accessed outside of the function block via a property, for example:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
// foot-pounds
METHOD PRIVATE CalculateTorque : REAL
VAR_INPUT
    rActualTorque : REAL; //0.1% of max torque 
END_VAR
VAR_INST
    fbMovingAverage : FB_MovingAverage;
END_VAR
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #6A9955">// foot-pounds</span></span>
<span class="line"><span style="color: #569CD6">METHOD</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">PRIVATE</span><span style="color: #D4D4D4"> CalculateTorque : </span><span style="color: #569CD6">REAL</span></span>
<span class="line"><span style="color: #D4D4D4">VAR_INPUT</span></span>
<span class="line"><span style="color: #D4D4D4">    rActualTorque : </span><span style="color: #569CD6">REAL</span><span style="color: #D4D4D4">; </span><span style="color: #6A9955">//0.1% of max torque </span></span>
<span class="line"><span style="color: #D4D4D4">END_VAR</span></span>
<span class="line"><span style="color: #D4D4D4">VAR_INST</span></span>
<span class="line"><span style="color: #D4D4D4">    fbMovingAverage : FB_MovingAverage;</span></span>
<span class="line"><span style="color: #D4D4D4">END_VAR</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Another very common return type is simply a BOOL. Of course, a BOOL can mean many things (sensor state, method complete successfully, etc.), so be sure to comment on what the return value means if it is not obvious!</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
// true = enable successful, false = interlocks active 
METHOD PUBLIC Enable : BOOL
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #6A9955">// true = enable successful, false = interlocks active </span></span>
<span class="line"><span style="color: #569CD6">METHOD</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">PUBLIC</span><span style="color: #D4D4D4"> Enable : BOOL</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Methods can also serve as a way of organizing code and maintaining readability in application code. This is an example of when a return is not needed. The following excerpt is taken from the OOP Extended Sample.&nbsp;</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
// Call of actions

    // Init
    General_Init();

    // Mode and state requests
    General_Requests();
    
    // Enable for power supply, compressed air control and buttons
    General_Enable();
    
    // Input variables of separating and sorting modules
    General_ModuleInputs();
    
    // Output variables
    General_SetOutput();
    ...
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #6A9955">// Call of actions</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Init</span></span>
<span class="line"><span style="color: #D4D4D4">    General_Init();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Mode and state requests</span></span>
<span class="line"><span style="color: #D4D4D4">    General_Requests();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Enable for power supply, compressed air control and buttons</span></span>
<span class="line"><span style="color: #D4D4D4">    General_Enable();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Input variables of separating and sorting modules</span></span>
<span class="line"><span style="color: #D4D4D4">    General_ModuleInputs();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Output variables</span></span>
<span class="line"><span style="color: #D4D4D4">    General_SetOutput();</span></span>
<span class="line"><span style="color: #D4D4D4">    ...</span></span>
<span class="line"></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
METHOD PRIVATE General_Init
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #569CD6">METHOD</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">PRIVATE</span><span style="color: #D4D4D4"> General_Init</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">A really powerful feature of Beckhoff is the ability to <a href="https://infosys.beckhoff.com/content/1033/tc3_plc_intro/7145472907.html?id=6105454089919227750" target="_blank">call methods</a> via ADS. This, in turn, makes methods&nbsp;able to be called via OPCUA.&nbsp;Head on over to our <a href="https://static.dmcinfo.com/latest-thinking/blog/id/10396/getting-started-with-opc-ua-in-beckhoff-twincat-3">blog</a>&nbsp;about setting up an OPCUA server if you have not already done so!</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
{attribute 'TcRpcEnable'}
METHOD PUBLIC MoveDistance : ST_Response
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #6A9955">{attribute &apos;TcRpcEnable&apos;}</span></span>
<span class="line"><span style="color: #569CD6">METHOD</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">PUBLIC</span><span style="color: #D4D4D4"> MoveDistance : ST_Response</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Here, I am using UaExpert to call the method.&nbsp;</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/CallMethod.png" alt=""/></figure>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/MethodResponse.png" alt=""/></figure>



<p class="wp-block-paragraph">This can make testing extremely efficient. No need to add debug bits to test your code, just call the method that is being tested!</p>



<p class="wp-block-paragraph">Another Beckhoff-specific implementation of a method is <a href="https://infosys.beckhoff.com/content/1033/tc3_plc_intro/5094414603.html?id=6967794353598129051" target="_blank" rel="noreferrer noopener">FB_init</a>. This allows for initialization of the function block before it is called. A simple use case for this is when project variants are used (another plug for one of our <a href="https://static.dmcinfo.com/latest-thinking/blog/id/10299/twincat-project-variants">blogs</a>!). Different initialized values can be used depending on the variant selected. For example, in the Simulation variant, the default conveyor speed is set to the maximum value to speed up any testing that is needed. Another common use case is initializing pointers and references to be used during runtime.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
METHOD FB_init : BOOL
VAR_INPUT
    bInitRetains : BOOL; 
    bInCopyCode : BOOL;  
END_VAR
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #569CD6">METHOD</span><span style="color: #D4D4D4"> FB_init : BOOL</span></span>
<span class="line"><span style="color: #D4D4D4">VAR_INPUT</span></span>
<span class="line"><span style="color: #D4D4D4">    bInitRetains : BOOL; </span></span>
<span class="line"><span style="color: #D4D4D4">    bInCopyCode : BOOL;  </span></span>
<span class="line"><span style="color: #D4D4D4">END_VAR</span></span>
<span class="line"></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
{IF defined(Simulation)}
    lrSpeedSetpoint := MAX_SPEED;
{ELSE}    
    lrSpeedSetpoint := 100;
{END_IF}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #6A9955">{IF defined(Simulation)}</span></span>
<span class="line"><span style="color: #D4D4D4">    lrSpeedSetpoint := MAX_SPEED;</span></span>
<span class="line"><span style="color: #6A9955">{ELSE}</span><span style="color: #D4D4D4">    </span></span>
<span class="line"><span style="color: #D4D4D4">    lrSpeedSetpoint := </span><span style="color: #B5CEA8">100</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #6A9955">{END_IF}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Obviously, this is just scratching the surface of what methods can do. There are varying schools of thought on how much logic a method should contain. Some implementations of methods simply move state machines from one state to another; other implementations may contain an entire sequencer inside a state. This depends on the architecture of the project.</p>



<p class="wp-block-paragraph">DMC is happy to discuss the implementation of your project and help decide which implementation of methods will work best for you!&nbsp;</p>



<h2 class="wp-block-heading" id="h-properties">Properties</h2>



<p class="wp-block-paragraph">Moving onto properties, a <a href="https://infosys.beckhoff.com/content/1033/tc3_plc_intro/2530335371.html?id=7678313929092874522" target="_blank">property</a>&nbsp;is an object attribute that <em>encapsulates </em>data and provides a controlled way to access or modify the data associated with it. Properties allow you to expose the internal state of an object while enforcing rules and logic for data access.</p>



<p class="wp-block-paragraph">Properties are implemented using getter and setter methods. A getter is a method used to retrieve the value of a private attribute of an object. A setter is a method used to modify the value of a private attribute of an object.</p>



<p class="wp-block-paragraph">Properties have&nbsp;the same access modifiers as the methods described above.</p>



<p class="wp-block-paragraph">A simple example of this would be the speed setpoint of the previously mentioned conveyor.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
// ft/min
PROPERTY PUBLIC lrSpeedSetpoint : LREAL
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #6A9955">// ft/min</span></span>
<span class="line"><span style="color: #569CD6">PROPERTY</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">PUBLIC</span><span style="color: #D4D4D4"> lrSpeedSetpoint : LREAL</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">The setter can have conditions to make sure the speed is set within the proper bounds. In this example, a negative number is rejected, and a speed greater than the maximum is set to the maximum speed. The getter simply returns the speed here; however, a getter could convert a raw signal into a useful value, for example:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
// "Set"
IF lrSpeedSetpoint >= 0 THEN
    _lrSpeedSetpoint := SEL(lrSpeedSetpoint > MAX_SPEED, lrSpeedSetpoint, MAX_SPEED);
END_IF
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #6A9955">// &quot;Set&quot;</span></span>
<span class="line"><span style="color: #569CD6">IF</span><span style="color: #D4D4D4"> lrSpeedSetpoint &gt;= </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">THEN</span></span>
<span class="line"><span style="color: #D4D4D4">    _lrSpeedSetpoint := SEL(lrSpeedSetpoint &gt; MAX_SPEED, lrSpeedSetpoint, MAX_SPEED);</span></span>
<span class="line"><span style="color: #D4D4D4">END_IF</span></span>
<span class="line"></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
// "Get" 
lrSpeedSetpoint := _lrSpeedSetpoint;
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #6A9955">// &quot;Get&quot; </span></span>
<span class="line"><span style="color: #D4D4D4">lrSpeedSetpoint := _lrSpeedSetpoint;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">To access properties, the following should be used:&nbsp;</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
// Access "Set" 
fbConveyor.lrSpeedSetpoint := 100; // 100 ft/min
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #6A9955">// Access &quot;Set&quot; </span></span>
<span class="line"><span style="color: #D4D4D4">fbConveyor.lrSpeedSetpoint := </span><span style="color: #B5CEA8">100</span><span style="color: #D4D4D4">; </span><span style="color: #6A9955">// 100 ft/min</span></span>
<span class="line"></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
// Access "Get" 
lrConveyorSpeedSetpoint:= fbConveyor.lrSpeedSetpoint;
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #6A9955">// Access &quot;Get&quot; </span></span>
<span class="line"><span style="color: #D4D4D4">lrConveyorSpeedSetpoint:= fbConveyor.lrSpeedSetpoint;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">If a property does not need either the getter or the setter, it can simply be deleted.</p>



<p class="wp-block-paragraph">From my personal experience, I have not seen properties used a ton. There are some specific situations where they are useful, but often there are several different ways to achieve the same functionality. Methods, on the other hand, are essential to building an OOP-based project.</p>



<p class="wp-block-paragraph">Look out for part 2, interfaces, coming soon!</p>



<p class="wp-block-paragraph"><strong>Learn more about DMC&#8217;s&nbsp;<a href="/services/manufacturing-automation-and-intelligence/plc-programming/beckhoff-and-twincat-3-programming">Beckhoff and TwinCAT 3 programming</a>&nbsp;expertise and&nbsp;<a href="/contact">contact us</a>&nbsp;for your next project.</strong></p>
<p>The post <a href="https://static.dmcinfo.com/blog/17364/beckhoff-oop-part-one-methods-and-properties/">Beckhoff OOP: Part One &#8211; Methods and Properties</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Getting started with C++ on a Beckhoff PLC &#8211; Part 2: Creating the ST/C++ Interface</title>
		<link>https://static.dmcinfo.com/blog/17475/getting-started-with-c-on-a-beckhoff-plc-part-2-creating-the-st-c-interface/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Sat, 17 Jun 2023 18:12:23 +0000</pubDate>
				<category><![CDATA[Beckhoff PLC]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[PLC]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[TwinCAT]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/17475/getting-started-with-c-on-a-beckhoff-plc-part-2-creating-the-st-c-interface/</guid>

					<description><![CDATA[<p>Other Installments in This Series: The second part of this series on how to run C++ real-time on a Beckhoff PLC will cover creating the interface that will host the C++ code, creating methods and data types within that interface, and how to access that interface from the structured text code. The C++ Interface is [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/17475/getting-started-with-c-on-a-beckhoff-plc-part-2-creating-the-st-c-interface/">Getting started with C++ on a Beckhoff PLC &#8211; Part 2: Creating the ST/C++ Interface</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><strong><u>Other Installments in This Series:</u></strong></p>



<ul class="wp-block-list">
<li><a href="https://static.dmcinfo.com/blog/17484/getting-started-with-c-on-a-beckhoff-plc-part-one-setup/">Getting started with C++ on a Beckhoff PLC &#8211; Part One: Setup</a></li>
</ul>



<p class="wp-block-paragraph">The second part of this series on how to run C++ real-time on a Beckhoff PLC will cover creating the interface that will host the C++ code, creating methods and data types within that interface, and how to access that interface from the structured text code.</p>



<p class="wp-block-paragraph">The C++ Interface is the same concept as interfaces in structured text programming on Beckhoff PLCs, however the interface is implemented through the C++ TMC file (TwinCAT Module Class Editor) instead of a POU.</p>



<p class="wp-block-paragraph">The interface will specify method declarations, return types, and the parameters needed, while the C++ file will provide the method definitions.</p>



<h2 class="wp-block-heading" id="h-table-of-contents">Table of Contents</h2>



<ol class="wp-block-list">
<li><a href="#h-creating-the-c-interface">Creating the C++ Interface</a></li>



<li><a href="#h-static-link-to-c-module">Static Link to C++ Module</a>
<ul class="wp-block-list">
<li><a href="#h-creating-the-c-tccom-module">Creating the C++ TcCOM Module</a></li>



<li><a href="#h-connect-the-c-interface-to-structured-text">Connect the C++ Interface to Structured Text</a></li>
</ul>
</li>



<li><a href="#h-dynamic-link-to-nbsp-c-module-nbsp">Dynamic&nbsp;Link to C++ Module</a></li>



<li><a href="#h-tips-and-tricks">Tips and Tricks</a></li>
</ol>



<h2 class="wp-block-heading" id="h-creating-the-c-interface">Creating the C++ Interface</h2>



<p class="wp-block-paragraph"><a href="#h-table-of-contents"><i>Back to Table of Contents</i></a></p>



<ol class="wp-block-list">
<li>To create the interface, open the .tmc file in the C++ project.</li>
</ol>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Getting-started-with-C__-on-Beckhoff-Pt-2-_tmc-file.png" alt="A screenshot of a computerDescription automatically generated"/></figure>



<ol class="wp-block-list">
<li></li>
</ol>



<p class="wp-block-paragraph">2. In the TMC editor, click Data Types and click &#8220;Adds a new interface ()&#8221;</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Adds-a-new-interface.png" alt="A screenshot of a computerDescription automatically generated"/></figure>



<p class="wp-block-paragraph">3. The interface will contain all the methods that will be made accessible. To add new methods, click the drop-down icon to the left of the interface and select &#8220;Methods&#8221;. The buttons in the ribbon can create, remove, reorganize, or copy and paste methods.</p>



<ol class="wp-block-list">
<li></li>
</ol>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Getting-started-with-C__-on-Beckhoff-Pt-2-Method-1_1.png" alt="A screenshot of a computerDescription automatically generated"/></figure>



<p class="wp-block-paragraph">4. Once a method has been created, double click it to edit its parameters and return type.</p>



<ol class="wp-block-list">
<li></li>
</ol>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Method-Parameters.png" alt="A screenshot of a computerDescription automatically generated"/></figure>



<p class="wp-block-paragraph"><strong>Note about custom data types:</strong></p>



<p class="wp-block-paragraph">a. While the TMC editor allows you to create structs in the module and set the interface method&#8217;s return data type to a struct, TwinCAT does not allow structs as a return data type in the structured text / C++ interface. Doing so will cause a <em>Structured return value not allowed in external function calls</em> error.</p>



<p class="wp-block-paragraph">b. Additionally, structs cannot be used as parameters in method calls either. This will cause a <em>Structured value types not allowed in external function calls</em> error.</p>



<p class="wp-block-paragraph">c. Because of this limitation, to return multiple values from a method, it is recommended to use pointers or references to your desired return value as parameters of the method. TwinCAT will pass these values by reference. </p>



<p class="wp-block-paragraph">5. When editing Method Parameters, TwinCAT allows you to specify parameters as pointers, pointer to pointers, or a reference.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-15_42_59-Getting-started-with-C__-on-Beckhoff-Pt-2-pointer-type.png" alt="A screenshot of a computerDescription automatically generated"/></figure>



<ol class="wp-block-list">
<li></li>
</ol>



<p class="wp-block-paragraph">6. Add all methods with return types and parameters to the interface. </p>



<ol class="wp-block-list">
<li></li>
</ol>



<p class="wp-block-paragraph">7. Once all methods are added, add the new interface to the TMC&#8217;s Implemented Interfaces section. This specifies that we are implementing the code for the interface within the C++ module. The interface created should appear in the list next to &#8220;(local)&#8221;.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-15_44_16-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Implemented-Interfaces.png" alt="A screenshot of a computerDescription automatically generated"/></figure>



<ol class="wp-block-list">
<li></li>
</ol>



<p class="wp-block-paragraph">8. Click the &#8220;Run TMC Code Generator&#8221; button and TwinCAT will automatically create function definitions and declarations in the .cpp file. The &#8220;Fun TMC Code Generator&#8221; can be run by clicking the button.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-15_58_02-Getting-started-with-C__-on-Beckhoff-Pt-2-TwinCAT-3-TMC-Code-Generator.png" alt="A screenshot of a computerDescription automatically generated"/></figure>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Getting-started-with-C__-on-Beckhoff-Pt-2-Run-TMC-Code-Generator.png" alt="A screenshot of a computerDescription automatically generated with medium confidence"/></figure>



<p class="wp-block-paragraph">a. The TMC Code Generator must be run any time you make changes to the TMC file (editing method parameters, return types, and adding new methods, etc.).</p>



<p class="wp-block-paragraph">b. If a previously generated method&#8217;s parameters or return type were edited, TwinCAT will move the program to the bottom of the .cpp file under an &lt;AutoGeneratedContent id=&#8221;Obsolete_ImplementationOf_IInterface1&#8243;&gt; tag, and provide an empty function implementation. You can copy the previous code and make any edits as necessary.</p>



<p class="wp-block-paragraph">9. Add the C++ code into the function definitions.</p>



<p class="wp-block-paragraph">10. Once all functions are added, compile the C++ code into a TMX file by right clicking the C++ Project and selecting &#8220;Publish Modules&#8221;. The Build Output of Visual Studio will show if the C++ project compiled successfully.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-TwinCAT-publish-modules.png" alt="A screenshot of a computerDescription automatically generated"/></figure>



<p class="wp-block-paragraph">After creating the C++ interface, it must be linked to the structured text by creating a proxy function block. The structured text function block will host an interface pointer to the C++ memory which will expose the methods defined in the TMC file and allow the function block to call the C++ functions.</p>



<p class="wp-block-paragraph">This can be done by creating a TcCOM object that is linked to a structured text FB (Section B) or can be dynamically created from within the structured text. (Section C).</p>



<h2 class="wp-block-heading" id="h-static-link-to-c-module">Static Link to C++ Module</h2>



<p class="wp-block-paragraph"><a href="#h-table-of-contents"><i>Back to Table of Contents</i></a></p>



<p class="wp-block-paragraph">The static link will create individual proxy function blocks for each instance of the C++ module. This is done by creating TcCOM modules for each instance desired.&nbsp;All instances&nbsp;must be created before runtime and cannot be created/deleted during runtime.&nbsp;</p>



<h3 class="wp-block-heading" id="h-creating-the-c-tccom-module">Creating the C++ TcCOM Module</h3>



<ol class="wp-block-list">
<li>After compiling the code, a C++ Module instance must be created. This can be added in the C++ project, or under System/TcCOM Objects.
<ul class="wp-block-list">
<li>In the C++ Project, right click the C++ project and click &#8220;Add new Item&#8221;. In the Insert TcCom Object popup, it will search the local project for the module&#8217;s TMC file. Select the module created and click OK.</li>



<li>If adding under System/TcCOM, TwinCAT will search your development PC (not the target PC) for the TMC file. Search for the module and verify that the file path is correct, then click OK. </li>



<li></li>
</ul>
</li>
</ol>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="900" height="459" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Getting-Started-with-C__-on-Beckhoff-Part-2-Add-New-Item.png" alt="A screenshot of a computer programDescription automatically generated with medium confidence" class="wp-image-17463" srcset="https://static.dmcinfo.com/wp-content/uploads/2025/05/Getting-Started-with-C__-on-Beckhoff-Part-2-Add-New-Item.png 900w, https://static.dmcinfo.com/wp-content/uploads/2025/05/Getting-Started-with-C__-on-Beckhoff-Part-2-Add-New-Item-300x153.png 300w, https://static.dmcinfo.com/wp-content/uploads/2025/05/Getting-Started-with-C__-on-Beckhoff-Part-2-Add-New-Item-768x392.png 768w" sizes="(max-width: 900px) 100vw, 900px" /></figure>



<p class="wp-block-paragraph">2. Double-click the Module Instance and select &#8220;Interfaces&#8221;. You should see your created interface in the list. This verifies that you have created your C++ interface and instance correctly. </p>



<p class="wp-block-paragraph">3. The TcCOM allows a system task to be assigned to the module in the &#8220;Context&#8221; tab; however, that is only necessary if you have cyclic code. If you are only providing interface methods, it is not required. </p>



<ol class="wp-block-list">
<li></li>
</ol>



<h3 class="wp-block-heading" id="h-connect-the-c-interface-to-structured-text">Connect the C++ Interface to Structured Text</h3>



<p class="wp-block-paragraph">Once a TcCOM module has been created for the C++ code, it must be linked to a structured text function block through an interface pointer. The function <a href="https://infosys.beckhoff.com/content/1033/tcplclib_tc3_module/1900117643.html?id=4396498500852015490" target="_blank" rel="noreferrer noopener">FW_ObjMgr_GetObjectInstance</a> can be used to create an interface pointer to an object instance upon function block initialization: FB_Init().</p>



<p class="wp-block-paragraph">Upon function block deletion, FB_Exit() is called which runs <a href="https://infosys.beckhoff.com/content/1033/tcplclib_tc3_module/1900190219.html?id=2960691403916095942" target="_blank" rel="noreferrer noopener">FW_SafeRelease</a> which releases the interface pointer memory. Note: this does not delete the C++ memory and any internal variables will be stored.</p>



<ol class="wp-block-list">
<li>Create a PLC Project if one does not exist.</li>



<li>Add a new POU for the C++ Interface.</li>
</ol>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_17_18-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Add-new-POU.png" alt="Add new POU"/></figure>



<p class="wp-block-paragraph">3. A popup should appear allowing you to input a name for the POU.</p>



<p class="wp-block-paragraph">4. Add the following vars and methods to the function block in the main FB:</p>



<pre class="wp-block-code"><code>
VAR
{attribute 'TcInitSymbol'}
oidInstance : OTCID;
//ipInterface is the name of the interface pointer. You can provide any name.
ipInterface : IInterface1;
hrInit : HRESULT;
END_VAR
}
</code></pre>



<p class="wp-block-paragraph">A. <strong>FB_Init()</strong> &#8211; This code connects the object specified at oidInstance with the interface specified at iid (in step 10) and provides the pointer to the interface in pipUnk. </p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
METHOD FB_init : BOOL
VAR_INPUT
	bInitRetains : BOOL; // if TRUE, the retain variables are initialized (warm start / cold start)
	bInCopyCode : BOOL;  // if TRUE, the instance afterwards gets moved into the copy code (online change)
END_VAR
//Implementation
IF NOT bInCopyCode THEN 
		IF ipInterface1 = 0 THEN
			hrInit := FW_ObjMgr_GetObjectInstance ( oid:=oidInstance,
													iid:=TC_GLOBAL_IID_LIST.IID_IInterface1,
													pipUnk:=ADR(ipInterface1) );
		END_IF
END_IF
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #569CD6">METHOD</span><span style="color: #D4D4D4"> FB_init : BOOL</span></span>
<span class="line"><span style="color: #D4D4D4">VAR_INPUT</span></span>
<span class="line"><span style="color: #D4D4D4">	bInitRetains : BOOL; </span><span style="color: #6A9955">// if TRUE, the retain variables are initialized (warm start / cold start)</span></span>
<span class="line"><span style="color: #D4D4D4">	bInCopyCode : BOOL;  </span><span style="color: #6A9955">// if TRUE, the instance afterwards gets moved into the copy code (online change)</span></span>
<span class="line"><span style="color: #D4D4D4">END_VAR</span></span>
<span class="line"><span style="color: #6A9955">//Implementation</span></span>
<span class="line"><span style="color: #569CD6">IF</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">NOT</span><span style="color: #D4D4D4"> bInCopyCode </span><span style="color: #569CD6">THEN</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">		</span><span style="color: #569CD6">IF</span><span style="color: #D4D4D4"> ipInterface1 = </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">THEN</span></span>
<span class="line"><span style="color: #D4D4D4">			hrInit := FW_ObjMgr_GetObjectInstance ( oid:=oidInstance,</span></span>
<span class="line"><span style="color: #D4D4D4">													iid:=TC_GLOBAL_IID_LIST.IID_IInterface1,</span></span>
<span class="line"><span style="color: #D4D4D4">													pipUnk:=ADR(ipInterface1) );</span></span>
<span class="line"><span style="color: #D4D4D4">		END_IF</span></span>
<span class="line"><span style="color: #D4D4D4">END_IF</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">[endif]-</p>



<p class="wp-block-paragraph">B. <strong>FB_Exit()</strong> &#8211; This code deletes the interface pointer. </p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
METHOD FB_exit : BOOL
VAR_INPUT
	bInCopyCode : BOOL; // if TRUE, the exit method is called for exiting an instance that is copied afterwards (online change).
END_VAR
//Implementation
IF NOT bInCopyCode THEN
	FW_SafeRelease(ADR(ipInterface1));
END_IF
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #569CD6">METHOD</span><span style="color: #D4D4D4"> FB_exit : BOOL</span></span>
<span class="line"><span style="color: #D4D4D4">VAR_INPUT</span></span>
<span class="line"><span style="color: #D4D4D4">	bInCopyCode : BOOL; </span><span style="color: #6A9955">// if TRUE, the exit method is called for exiting an instance that is copied afterwards (online change).</span></span>
<span class="line"><span style="color: #D4D4D4">END_VAR</span></span>
<span class="line"><span style="color: #6A9955">//Implementation</span></span>
<span class="line"><span style="color: #569CD6">IF</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">NOT</span><span style="color: #D4D4D4"> bInCopyCode </span><span style="color: #569CD6">THEN</span></span>
<span class="line"><span style="color: #D4D4D4">	FW_SafeRelease(ADR(ipInterface1));</span></span>
<span class="line"><span style="color: #D4D4D4">END_IF</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">5. The C++ Methods can now be called the interface pointer&#8217;s methods. These method calls can be made in the FB&#8217;s main implementation or any FB method or action.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C++</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>IF ipInterface &lt;> 0 THEN
    // ipInterface is the interface pointer.
    getPrivInt := ipInterface.SetPrivInt(5);
END_IF</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">IF ipInterface &lt;&gt; </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4"> THEN</span></span>
<span class="line"><span style="color: #6A9955">    // ipInterface is the interface pointer.</span></span>
<span class="line"><span style="color: #D4D4D4">    getPrivInt := </span><span style="color: #9CDCFE">ipInterface</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">SetPrivInt</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">5</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">END_IF</span></span></code></pre></div>



<pre class="wp-block-preformatted">
6. Add an instance of the FB to MAIN or any other POUs. Once all methods are added, click "Build" and see if the project compiles successfully. Once built, click the PLC instance and there will be a tab called "Symbol Initialization". Select the oildInstance for the C++ object instance in the drop-down list.</pre>



<p class="wp-block-paragraph">7. Click &#8220;Apply to config&#8221; to download the structure text and C++ code to the PLC.</p>



<h2 class="wp-block-heading" id="h-dynamic-link-to-nbsp-c-module-nbsp">Dynamic Link to&nbsp;C++ Module&nbsp;</h2>



<p class="wp-block-paragraph"><a href="#h-table-of-contents"><i>Back to Table of Contents</i></a></p>



<p class="wp-block-paragraph">Instead of creating a TcCOM object that is an instance of the C++ code, the structured text function block can also dynamically create the TcCOM module during initialization: FB_Init(), or any method. This can be done using Twincat’s function <a href="https://infosys.beckhoff.com/content/1033/tcplclib_tc3_module/1899956875.html?id=6855305224713025932">FW_ObjMgr_CreateAndInitInstance</a>.</p>



<p class="wp-block-paragraph">Upon function block deletion, FB_Exit() is called which will run <a href="https://infosys.beckhoff.com/content/1033/tcplclib_tc3_module/1900069259.html?id=7445048424541430396" target="_blank" rel="noreferrer noopener">FW_ObjMgr_DeleteInstance</a>.&nbsp;</p>



<ol class="wp-block-list">
<li>Click the &#8220;TcCOM Objects&#8221; and select &#8220;Class Factories&#8221;. This list displays all C++ drivers on the computer. Ensure that the C++ driver you wish to implement has &#8220;Load&#8221; checked.</li>
</ol>



<figure class="wp-block-image size-full"><img decoding="async" width="900" height="226" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_22_15-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Load-Driver.png" alt="2023 06 17 16 22 15 Getting started with C on Beckhoff Pt 2 AutoRecovered Load Driver" class="wp-image-17467" srcset="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_22_15-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Load-Driver.png 900w, https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_22_15-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Load-Driver-300x75.png 300w, https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_22_15-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Load-Driver-768x193.png 768w" sizes="(max-width: 900px) 100vw, 900px" /></figure>



<p class="wp-block-paragraph">2. Create a structured text function block. This function block is what will create the C++ interface instance. </p>



<p class="wp-block-paragraph">3. Add the Tc2_Utilities library to your project references. This library is needed for the &#8220;STRING_TO_GUID&#8221; function used in FB_Init().</p>



<figure class="wp-block-image size-full"><img decoding="async" width="900" height="296" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_22_41-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Add-Library.png" alt="A screenshot of a computerDescription automatically generated with medium confidence" class="wp-image-17468" srcset="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_22_41-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Add-Library.png 900w, https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_22_41-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Add-Library-300x99.png 300w, https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_22_41-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Add-Library-768x253.png 768w" sizes="(max-width: 900px) 100vw, 900px" /></figure>



<p class="wp-block-paragraph">&nbsp;a. Under References, right click and select &#8220;Add library&#8221;.</p>



<p class="wp-block-paragraph">b. Search &#8220;Utilities&#8221; at the top and add Tc2_Utilities.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">4. Next, get the GUID and Library ID of the interface. This can be done by creating a TcCOM object and copying the GUID and Class ID. (instructions on how to create a TcCOM object can be found&nbsp;in part B). <!-- width="515" height="219" src="file:///C:/Users/aizhat/AppData/Local/Temp/msohtmlclip1/01/clip_image046.jpg" alt="A screenshot of a computer

Description automatically generated" /--></p>



<p class="wp-block-paragraph">5. Add the following functions and code to your function block:<!-- -->In FB’s implementation.</p>



<p class="wp-block-paragraph">a. In FB&#8217;s implementation. The &lt;GUID&gt; is the GUID specified in the previous step, and &lt;Library ID&gt; is the text in the parentheses in Class Factory. </p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>FUNCTION_BLOCK FB_CppDynamicLink VAR_OUTPUT   // this does not have to be an array     
ipInterface  : ARRAY &#91;1..5&#93; OF CppInterface;     
numInterfaces : INT := 1; 
END_VAR 
VAR     
  objName : STRING;     
  classId : CLSID := STRING_TO_GUID('&lt;GUID>');     
  sLibraryId  : STRING := '&lt;Class ID>';     
  classIdVersioned : CLSID;     
  iid : IID := TC_GLOBAL_IID_LIST.IID_&lt;InterfaceName>;     
  hrInit  : HRESULT; 
END_VAR</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">FUNCTION_BLOCK FB_CppDynamicLink VAR_OUTPUT   </span><span style="color: #6A9955">// this does not have to be an array     </span></span>
<span class="line"><span style="color: #D4D4D4">ipInterface  : </span><span style="color: #569CD6">ARRAY</span><span style="color: #D4D4D4"> &#91;</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">.</span><span style="color: #B5CEA8">.5</span><span style="color: #D4D4D4">&#93; </span><span style="color: #569CD6">OF</span><span style="color: #D4D4D4"> CppInterface;     </span></span>
<span class="line"><span style="color: #D4D4D4">numInterfaces : INT := </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">; </span></span>
<span class="line"><span style="color: #D4D4D4">END_VAR </span></span>
<span class="line"><span style="color: #569CD6">VAR</span><span style="color: #D4D4D4">     </span></span>
<span class="line"><span style="color: #D4D4D4">  objName : </span><span style="color: #569CD6">STRING</span><span style="color: #D4D4D4">;     </span></span>
<span class="line"><span style="color: #D4D4D4">  classId : CLSID := STRING_TO_GUID(</span><span style="color: #CE9178">&apos;&lt;GUID&gt;&apos;</span><span style="color: #D4D4D4">);     </span></span>
<span class="line"><span style="color: #D4D4D4">  sLibraryId  : </span><span style="color: #569CD6">STRING</span><span style="color: #D4D4D4"> := </span><span style="color: #CE9178">&apos;&lt;Class ID&gt;&apos;</span><span style="color: #D4D4D4">;     </span></span>
<span class="line"><span style="color: #D4D4D4">  classIdVersioned : CLSID;     </span></span>
<span class="line"><span style="color: #D4D4D4">  iid : IID := TC_GLOBAL_IID_LIST.IID_&lt;InterfaceName&gt;;     </span></span>
<span class="line"><span style="color: #D4D4D4">  hrInit  : HRESULT; </span></span>
<span class="line"><span style="color: #D4D4D4">END_VAR</span></span></code></pre></div>



<p class="wp-block-paragraph">b. FB_Init() &#8211; This code will create C++ instance upon function block&#8217;s initialization. This code can also be adapted to create additional instances during runtime. </p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Pascal</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&#91;Declaration&#93; 
METHOD FB_init : BOOL VAR_INPUT bInitRetains : BOOL; // if TRUE, the retain variables are initialized (warm start / cold start) 
bInCopyCode : BOOL; // if TRUE, the instance afterwards gets moved into the copy code (online change) 
sObjName : STRING; 
eObjState : TCOM_STATE; 
END_VAR &#91;Implementation&#93; 
IF NOT bInCopyCode THEN objName := sObjName; 
  F_GetClassIdVersioned(sLibraryId := sLibraryId, clsId := classId, clsIdVersioned:=classIdVersioned); 
  hrInit := FW_ObjMgr_CreateAndInitInstance( clsId := classIdVersioned, iid := iid, pipUnk := ADR(ipInterface) + SIZEOF(ipInterface&#91;1&#93;)*(numInterfaces-1), objId := OTCID_CreateNewId, parentId:= TwinCAT_SystemInfoVarList._AppInfo.ObjId, name := sObjName, state := eObjState, pInitData:= 0); 
END_IF</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&#91;Declaration&#93; </span></span>
<span class="line"><span style="color: #569CD6">METHOD</span><span style="color: #D4D4D4"> FB_init : BOOL VAR_INPUT bInitRetains : BOOL; </span><span style="color: #6A9955">// if TRUE, the retain variables are initialized (warm start / cold start) </span></span>
<span class="line"><span style="color: #D4D4D4">bInCopyCode : BOOL; </span><span style="color: #6A9955">// if TRUE, the instance afterwards gets moved into the copy code (online change) </span></span>
<span class="line"><span style="color: #D4D4D4">sObjName : </span><span style="color: #569CD6">STRING</span><span style="color: #D4D4D4">; </span></span>
<span class="line"><span style="color: #D4D4D4">eObjState : TCOM_STATE; </span></span>
<span class="line"><span style="color: #D4D4D4">END_VAR &#91;</span><span style="color: #569CD6">Implementation</span><span style="color: #D4D4D4">&#93; </span></span>
<span class="line"><span style="color: #569CD6">IF</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">NOT</span><span style="color: #D4D4D4"> bInCopyCode </span><span style="color: #569CD6">THEN</span><span style="color: #D4D4D4"> objName := sObjName; </span></span>
<span class="line"><span style="color: #D4D4D4">  F_GetClassIdVersioned(sLibraryId := sLibraryId, clsId := classId, clsIdVersioned:=classIdVersioned); </span></span>
<span class="line"><span style="color: #D4D4D4">  hrInit := FW_ObjMgr_CreateAndInitInstance( clsId := classIdVersioned, iid := iid, pipUnk := ADR(ipInterface) + SIZEOF(ipInterface&#91;</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">&#93;)*(numInterfaces-</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">), objId := OTCID_CreateNewId, parentId:= TwinCAT_SystemInfoVarList._AppInfo.ObjId, </span><span style="color: #569CD6">name</span><span style="color: #D4D4D4"> := sObjName, state := eObjState, pInitData:= </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">); </span></span>
<span class="line"><span style="color: #D4D4D4">END_IF</span></span></code></pre></div>



<p class="wp-block-paragraph">c. FB_Exit()</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">ST</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&#91;Declaration&#93;
METHOD FB_exit : BOOL
VAR_INPUT
    bInCopyCode : BOOL; // if TRUE, the exit method is called for exiting an instance that is copied afterwards (online change).
END_VAR
VAR
    i : INT;
END_VAR
&#91;Implementation&#93;
IF NOT bInCopyCode THEN
    FOR i := 1 TO 5 DO
        IF ipInterface&#91;i&#93; &lt;> 0 THEN
            FW_ObjMgr_DeleteInstance(ADR(ipInterface) + SIZEOF(ipInterface&#91;1&#93;)*(numInterfaces-1));
        END_IF
    END_FOR
END_IF
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&#91;Declaration&#93;</span></span>
<span class="line"><span style="color: #569CD6">METHOD</span><span style="color: #D4D4D4"> FB_exit : BOOL</span></span>
<span class="line"><span style="color: #D4D4D4">VAR_INPUT</span></span>
<span class="line"><span style="color: #D4D4D4">    bInCopyCode : BOOL; </span><span style="color: #6A9955">// if TRUE, the exit method is called for exiting an instance that is copied afterwards (online change).</span></span>
<span class="line"><span style="color: #D4D4D4">END_VAR</span></span>
<span class="line"><span style="color: #569CD6">VAR</span></span>
<span class="line"><span style="color: #D4D4D4">    i : INT;</span></span>
<span class="line"><span style="color: #D4D4D4">END_VAR</span></span>
<span class="line"><span style="color: #D4D4D4">&#91;</span><span style="color: #569CD6">Implementation</span><span style="color: #D4D4D4">&#93;</span></span>
<span class="line"><span style="color: #569CD6">IF</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">NOT</span><span style="color: #D4D4D4"> bInCopyCode </span><span style="color: #569CD6">THEN</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">FOR</span><span style="color: #D4D4D4"> i := </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">TO</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">5</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">DO</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">IF</span><span style="color: #D4D4D4"> ipInterface&#91;i&#93; &lt;&gt; </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">THEN</span></span>
<span class="line"><span style="color: #D4D4D4">            FW_ObjMgr_DeleteInstance(ADR(ipInterface) + SIZEOF(ipInterface&#91;</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">&#93;)*(numInterfaces-</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">));</span></span>
<span class="line"><span style="color: #D4D4D4">        END_IF</span></span>
<span class="line"><span style="color: #D4D4D4">    END_FOR</span></span>
<span class="line"><span style="color: #D4D4D4">END_IF</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">6. Add all function block methods to call the C++ methods as desired. The example at the bottom of the article shows how an internal C++ variable can be modified and accessed from the structured text.</p>



<p class="wp-block-paragraph">7. Once the proxy function block is made, create an instance of the FB in MAIN or any other program. Any of the proxy function block&#8217;s methods can be called from that program.&nbsp;</p>



<h2 class="wp-block-heading" id="h-tips-and-tricks">Tips and Tricks</h2>



<p class="wp-block-paragraph"><a href="#h-table-of-contents"><i>Back to Table of Contents</i></a></p>



<ol class="wp-block-list">
<li><!-- -->While doable in C++ real time code, it may be easier to do any file IO (Reading/Writing from CSV) within the structured text and passing the read data to the C++ through a method call.&nbsp;</li>



<li><!-- -->TwinCAT had difficulty passing in 2D array pointers from Structured Text to C++. Because of this, I found the best way was to split the 2D array within the structured text into multiple 1D arrays that are passed in, and a Boolean to flag when it is the last row in the 2D array.<!-- --></li>



<li>To debug the C++, Follow these steps:<!-- --></li>
</ol>



<p class="wp-block-paragraph">a. Build the C++ project in Debug instead of Release.</p>



<p class="wp-block-paragraph"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_25_20-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Debug.png"> <!-- width="555" height="560" src="file:///C:/Users/aizhat/AppData/Local/Temp/msohtmlclip1/01/clip_image058.jpg" alt="A screenshot of a computer

Description automatically generated" /--></p>



<p class="wp-block-paragraph">b. In the C++ Node settings, select the Enable C++ Debugger checkbox.</p>



<figure class="wp-block-image size-full"><img decoding="async" width="900" height="571" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_25_45-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Enable-C-__-Debugger.png" alt="2023 06 17 16 25 45 Getting started with C on Beckhoff Pt 2 AutoRecovered Enable C Debugger" class="wp-image-17470" srcset="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_25_45-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Enable-C-__-Debugger.png 900w, https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_25_45-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Enable-C-__-Debugger-300x190.png 300w, https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_25_45-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Enable-C-__-Debugger-768x487.png 768w" sizes="(max-width: 900px) 100vw, 900px" /></figure>



<p class="wp-block-paragraph">c. Right click your C++ project, go to Debug and click &#8220;Start New Instance&#8221;.</p>



<figure class="wp-block-image size-full"><img decoding="async" width="700" height="710" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_26_23-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Start-new-instance_1.png" alt="2023 06 17 16 26 23 Getting started with C on Beckhoff Pt 2 AutoRecovered Start new instance 1" class="wp-image-17471" srcset="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_26_23-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Start-new-instance_1.png 700w, https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_26_23-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Start-new-instance_1-296x300.png 296w" sizes="(max-width: 700px) 100vw, 700px" /></figure>



<p class="wp-block-paragraph">d. The C++ Debugger should start if you are running the C++ code. Keep in mind that the step controls for the C++ debugger are different from the Structured Text step controls and PLC controls. These are the specific controls for debugging the C++ :</p>



<figure class="wp-block-image size-full"><img decoding="async" width="900" height="70" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_27_59-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Controls.png" alt="2023 06 17 16 27 59 Getting started with C on Beckhoff Pt 2 AutoRecovered Controls" class="wp-image-17472" srcset="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_27_59-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Controls.png 900w, https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_27_59-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Controls-300x23.png 300w, https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_27_59-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Controls-768x60.png 768w" sizes="(max-width: 900px) 100vw, 900px" /></figure>



<p class="wp-block-paragraph">4. Running multiple instances of the C++ Module are allowed and will have separate memory from one another. This can be done by:</p>



<p class="wp-block-paragraph">a. Creating multiple TcCOM objects and FB instances as described in Section B. Once all new FB instances are made, select the correct OID for each instances in the Symbol Initialization page. (Step 7 of Part B) Note: Both TcCOM objects are C++ project Instances are allowed.</p>



<figure class="wp-block-image size-full"><img decoding="async" width="900" height="89" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_28_38-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Tcom-options-and-Project-instances.png" alt="2023 06 17 16 28 38 Getting started with C on Beckhoff Pt 2 AutoRecovered Tcom options and Project instances" class="wp-image-17473" srcset="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_28_38-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Tcom-options-and-Project-instances.png 900w, https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_28_38-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Tcom-options-and-Project-instances-300x30.png 300w, https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_28_38-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-Tcom-options-and-Project-instances-768x76.png 768w" sizes="(max-width: 900px) 100vw, 900px" /></figure>



<p class="has-text-align-center wp-block-paragraph"><em>Figure 1: Object 1 and 2 are TcCOM objects, while Untitled3_Obj1 is a C++ Project instance.</em></p>



<p class="wp-block-paragraph">b. Creating multiple instances of the dynamic function block as described in Section C. Because the function block dynamically creates the C++ instances, the oidInstances do not need to be set. The sObjName can be modified however, it is not required. Both instances will be unique.</p>



<p class="wp-block-paragraph">c. A mix of dynamic and static instances.</p>



<figure class="wp-block-image size-full"><img decoding="async" width="900" height="359" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_33_02-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-static-and-dynamic-instances.png" alt="2023 06 17 16 33 02 Getting started with C on Beckhoff Pt 2 AutoRecovered static and dynamic instances" class="wp-image-17474" srcset="https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_33_02-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-static-and-dynamic-instances.png 900w, https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_33_02-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-static-and-dynamic-instances-300x120.png 300w, https://static.dmcinfo.com/wp-content/uploads/2025/05/2023-06-17-16_33_02-Getting-started-with-C__-on-Beckhoff-Pt-2-AutoRecovered-static-and-dynamic-instances-768x306.png 768w" sizes="(max-width: 900px) 100vw, 900px" /></figure>



<p class="wp-block-paragraph">&nbsp;</p>



<p class="wp-block-paragraph"><strong>Learn more about our&nbsp;<a href="/services/manufacturing-automation-and-intelligence/plc-programming/beckhoff-and-twincat-3-programming">Beckhoff and TwinCAT 3 programming</a>&nbsp;expertise and&nbsp;<a href="/contact">contact us</a>&nbsp;for your next project.</strong></p>



<p class="wp-block-paragraph"><!--![endif]----></p>
<p>The post <a href="https://static.dmcinfo.com/blog/17475/getting-started-with-c-on-a-beckhoff-plc-part-2-creating-the-st-c-interface/">Getting started with C++ on a Beckhoff PLC &#8211; Part 2: Creating the ST/C++ Interface</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Getting started with C++ on a Beckhoff PLC &#8211; Part One: Setup</title>
		<link>https://static.dmcinfo.com/blog/17484/getting-started-with-c-on-a-beckhoff-plc-part-one-setup/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Sat, 17 Jun 2023 12:54:34 +0000</pubDate>
				<category><![CDATA[Beckhoff PLC]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[PLC]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[TwinCAT]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/17484/getting-started-with-c-on-a-beckhoff-plc-part-one-setup/</guid>

					<description><![CDATA[<p>Beckhoff PLCs are one of the few industrial PLCs that allow you to run real-time C++ directly on the PLC hardware. This allows for C++ code to run cyclically on a separate system task, or as a TcCOM object allowing for function calls from structured text. This guide will cover how to create the external [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/17484/getting-started-with-c-on-a-beckhoff-plc-part-one-setup/">Getting started with C++ on a Beckhoff PLC &#8211; Part One: Setup</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/plc-programming/beckhoff-and-twincat-3-programming">Beckhoff PLCs</a> are one of the few industrial PLCs that allow you to run real-time C++ directly on the PLC hardware. This allows for C++ code to run cyclically on a separate system task, or as a TcCOM object allowing for function calls from structured text.</p>



<p class="wp-block-paragraph">This guide will cover how to create the external interface and how to make C++ function calls and algorithms within your PLC program.</p>



<h2 id="h-steps" class="wp-block-heading"><a id="Steps List" name="Steps List">Steps</a></h2>



<ol class="wp-block-list">
<li><a href="#Setting up Twincat C++ IDE">Setting up the TwinCAT C++ IDE</a></li>



<li><a href="#Step 2: Create C++ and PLC programs">Creating your C++ and PLC programs.</a></li>



<li><a href="#Step 3: Adding Twincat Test Certificate">Adding a Test Signature Certificate.</a></li>
</ol>



<h2 id="h-step-1-setting-up-twincat-c-ide" class="wp-block-heading"><a id="Setting up Twincat C++ IDE" name="Setting up Twincat C++ IDE">Step 1: Setting up TwinCAT C++ IDE</a></h2>



<p class="wp-block-paragraph"><a href="#Steps List"><i>Back to Steps List</i></a></p>



<p class="wp-block-paragraph">While structured text development on TwinCAT can be done within the TwinCAT XAE Shell, TwinCAT C++ development must be done within Visual Studio 2019 with the TwinCAT extensions installed. If&nbsp;a TwinCAT solution with a C++ project is opened in&nbsp;XAE shell, you will be unable to view&nbsp;or edit the C++ code. TwinCAT integration will support&nbsp;Visual Studio 2022 in build 4026.</p>



<p class="wp-block-paragraph">If&nbsp;XAE Shell was&nbsp;installed before Visual Studio 2019, XAE shell must be uninstalled before installing Visual Studio, then XAE Shell can be reinstalled with the integration added.</p>



<p class="wp-block-paragraph">You can follow <a href="https://infosys.beckhoff.com/content/1033/tc3_installation/179467147.html?id=4514876775714218857">TwinCAT’s guide on integrating</a> with Visual Studio.</p>



<h2 id="h-step-2-creating-the-c-and-plc-programs" class="wp-block-heading"><a id="Step 2: Create C++ and PLC programs" name="Step 2: Create C++ and PLC programs">Step 2: Creating the C++ and PLC programs</a></h2>



<p class="wp-block-paragraph"><a href="#Steps List"><i>Back to Steps List</i></a></p>



<p class="wp-block-paragraph">The C++ integration can be added to a new or existing PLC program. Here&#8217;s a <a href="https://static.dmcinfo.com/latest-thinking/blog/id/10162/getting-started-with-a-beckhoff-plc-part-one--setup" type="link" id="https://static.dmcinfo.com/latest-thinking/blog/id/10162/getting-started-with-a-beckhoff-plc-part-one--setup">series of DMC guides</a> on how to set up and connect to a TwinCAT PLC.</p>



<p class="wp-block-paragraph">To add or create the C++ project:&nbsp;</p>



<ol class="wp-block-list">
<li>Under the C++ node of the solution, right click and select “Add New Item…”</li>
</ol>



<p class="wp-block-paragraph"><p style="margin-left:.25in;"></p></p>



<ol class="wp-block-list">
<li value="2">A popup will appear displaying the different types of TwinCAT C++ Projects.
 

<ol class="wp-block-list" style="list-style-type:lower-alpha;">
  

<li>Select &ldquo;Versioned C++ Project&rdquo; to create an interface accessible by structured text.</li>


  

<li>&ldquo;Driver projects&rdquo; are no longer recommended by TwinCAT and have fewer features compared to &ldquo;Versioned C++ Projects&rdquo;.</li>


  

<li>&ldquo;Static Library Projects&rdquo; create static libraries that create functions and classes that can be accessed from other C++ projects; however, they cannot create an interface accessible from structured text code.</li>


 </ol>


 </li>



<li>For this external interface, I will select &#8220;Versioned C++ Project&#8221;.</li>



<li>A popup will appear asking what type of Module Class to add a preset configuration.
 
 
<ol class="wp-block-list" style="list-style-type:lower-alpha;">
  

<li>To create a project that provides functions to call from structured text, select &ldquo;TwinCAT Module Class for RT Context&rdquo;.&nbsp;</li>


  

<li>The Cyclic Caller, Cyclic IO, and Data Pointer options all create a CyclicUpdate() function that can be attached to a task and have C++ run cyclically. This will run C++ code every scan.</li>


 </ol>
</li>
</ol>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Getting-Started-with-C__-On-Beckhoff-Module-Class-Options_1.png" alt=""/></figure>



<ol class="wp-block-list">
<li value="4">Enter a name and click OK.</li>
</ol>



<h2 id="h-step-3-adding-a-twincat-test-certificate" class="wp-block-heading"><a id="Step 3: Adding Twincat Test Certificate" name="Step 3: Adding Twincat Test Certificate">Step 3: Adding a TwinCAT Test Certificate</a></h2>



<p class="wp-block-paragraph"><a href="#Steps List"><i>Back to Steps List</i></a></p>



<p class="wp-block-paragraph">To run C++ programs on the PLC, a certificate must be added to ensure all C++ code is verified. TwinCAT allows for officially signed certificates, but a test certificate is sufficient for developing and testing code. TwinCAT recommends that all new projects use Versioned C++ projects, which requires the new TwinCAT Certificate. If developing software that uses the older &#8220;Driver Project&#8221;, then an Operating System certificate is needed instead.</p>



<p class="wp-block-paragraph">For more information about Driver signing, reference the <a href="https://infosys.beckhoff.com/content/1033/tc3_c/110691083.html?id=370147429722095671" target="_blank" rel="noreferrer noopener">Beckhoff Information System</a>.</p>



<p class="wp-block-paragraph">To add a new test certificate for a C++ Versioned Project:</p>



<ol class="wp-block-list">
<li>In Visual Studio 2019, go to Extensions/TwinCAT/Software Protection.&nbsp;In XAE Shell, go to TwinCAT/Software Protection.</li>
</ol>



<p class="wp-block-paragraph"><p style="margin-left:.5in;"></p></p>



<ol class="wp-block-list">
<li value="2">In the wizard, click &ldquo;Create New&hellip;&rdquo;&nbsp;and fill out the OEM name, Unique Name, and select the checkbox for &ldquo;Sign TwinCAT C++ Executables (.tmx). Click &quot;Yes&quot; on the popup that appears.</li>
</ol>



<p class="wp-block-paragraph"><p style="margin-left:.5in;"></p></p>



<ol class="wp-block-list">
<li value="4">Click &ldquo;Start&rdquo; and save the file in the default location&nbsp;(C:/TwinCAT/3.1/CustomConfig/Certificates/).&nbsp;</li>



<li value="5">Enter a password.&nbsp;
 

<ol class="wp-block-list">
  

<li>It is recommended to use the <a href="http://infosys.beckhoff.com/english.php?content=../content/1033/tc3_c/6829815563.html&amp;id=5788251524726684479">TcSignTool </a>to create the test signature password as TwinCAT will store the password in plaintext in the project file which can be easily shared.</li>


 </ol>


 </li>



<li value="6">Once the certificate has been created, it needs to be added to&nbsp;the C++ project. Right click the C++ Project and click &quot;Properties.&quot; Under the &ldquo;Tc Sign&rdquo; tab, select &quot;Yes&quot; for TwinCAT signing, and enter the certificate name and password.</li>
</ol>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Getting-Started-with-C__-On-Beckhoff-TwinCAT-Certificate-Name.png" alt=""/></figure>



<ol class="wp-block-list">
<li value="8">Because these test certificates are not countersigned by Beckhoff, the target PLC must be put into test mode to run the C++ code. Once the certificates have been countersigned by Beckhoff, your target PLC will not need to be in test mode.
 

<ol class="wp-block-list">
  

<li>On your Target PLC, open Command Prompt with Administrator privileges.</li>


  

<li>Run &ldquo;bcdedit /set testsigning yes&rdquo; in Command Prompt (Admin).</li>


  

<li>Restart your computer/PLC.</li>


  

<li>The Target PLC will now allow test certificate-signed C++ code to run on the PLC.</li>


 </ol>


 </li>



<li value="9">Right click the C++ Project and click &ldquo;Publish Modules&rdquo;. It should create an error that says the certificate is not valid or ADS has failed.</li>



<li value="10">Open (C:/TwinCAT/3.1/Target/OemCertificates) on the target PLC and locate the file with the same name as the certificate&rsquo;s &ldquo;Unique Name&rdquo;.</li>



<li value="11">Double click the file to add the certificate to Window&rsquo;s certificate registry. The &quot;Publish Modules&quot; button should now work, and the C++ project&nbsp;can build and run on your machine.&nbsp;</li>
</ol>



<p class="wp-block-paragraph"><p style="margin-left:.5in;"></p></p>



<p class="wp-block-paragraph"><p style="margin-left:.5in;">&nbsp;</p></p>



<p class="wp-block-paragraph"><p style="margin-left:.5in;">Now that the IDE and test certificate have been configured, the C++ project can be configured with the desired functions and interfaces and linked to a structured text function block, which will be covered in part two of this blog series.</p></p>



<p class="wp-block-paragraph"><strong>Learn more about our <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/plc-programming/beckhoff-and-twincat-3-programming">Beckhoff and TwinCAT 3 Programming</a> expertise and <a href="https://static.dmcinfo.com/contact/" type="page" id="411">contact us</a> for your next project.</strong></p>
<p>The post <a href="https://static.dmcinfo.com/blog/17484/getting-started-with-c-on-a-beckhoff-plc-part-one-setup/">Getting started with C++ on a Beckhoff PLC &#8211; Part One: Setup</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Beckhoff PLC to PLC Communication Using EAP &#8211;  A Starter Guide</title>
		<link>https://static.dmcinfo.com/blog/17760/beckhoff-plc-to-plc-communication-using-eap-a-starter-guide/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Tue, 07 Mar 2023 11:37:39 +0000</pubDate>
				<category><![CDATA[Beckhoff PLC]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[PLC]]></category>
		<category><![CDATA[Beckhoff]]></category>
		<category><![CDATA[EAP]]></category>
		<category><![CDATA[Ethernet IP]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[PLC Communication]]></category>
		<category><![CDATA[TwinCAT]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/17760/beckhoff-plc-to-plc-communication-using-eap-a-starter-guide/</guid>

					<description><![CDATA[<p>Beckhoff&#8217;s Industrial Personal Computers (IPCs) allow for easy configuration into a wide variety of PLC-to-PLC communications. Internal links between IPCs running TwinCAT XAR are the simplest and will be the first that this series of articles explore. This article demonstrates a holistic approach to establishing a connection between two&#160;Beckhoff IPCs. IPC Configuration: All PLCs mentioned [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/17760/beckhoff-plc-to-plc-communication-using-eap-a-starter-guide/">Beckhoff PLC to PLC Communication Using EAP &#8211;  A Starter Guide</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">Beckhoff&rsquo;s Industrial Personal Computers (IPCs) allow for easy configuration into a wide variety of PLC-to-PLC communications. Internal links between IPCs running TwinCAT XAR are the simplest and will be the first that this series of articles explore.</p>

<p class="wp-block-paragraph">This article demonstrates a holistic approach to establishing a connection between two&nbsp;Beckhoff IPCs.</p>

<h2 class="wp-block-heading">IPC Configuration:</h2>

<p class="wp-block-paragraph">All PLCs mentioned are the BECKHOFF C6017 model.</p>

<p class="wp-block-paragraph">In order to &ldquo;discover&rdquo; another PLC, the Beckhoff IPC will need to have its network and port configured to be visible across an ethernet or network connection. In this example I will be using a PLC that is networked to an internal server with 20 to&nbsp;40 other Beckhoff IPCs.</p>

<p class="wp-block-paragraph"><strong><u>Process:</u></strong></p>

<ol class="wp-block-list">
 <li>Connect the Beckhoff IPC to a monitor and peripherals to control the system. This specific model calls for a Display Port (DP) connection and any USB integrated keyboard and mouse.</li>
</ol>

<ol class="wp-block-list" start="2">
 <li>Sign into the IPC. If no configuration has been set, this will be Beckhoff&rsquo;s default login:
 <ol class="wp-block-list" style="list-style-type:lower-alpha;">
  <li>Username: ADMINISTRATOR</li>
  <li>Password: 1</li>
 </ol>
 </li>
</ol>

<ol class="wp-block-list" start="3">
 <li>If this is your first time accessing the PLC, click&nbsp;<a href="https://static.dmcinfo.com/latest-thinking/blog/id/10162/getting-started-with-a-beckhoff-plc-part-one--setup#Install%20Software" target="_blank">HERE</a>&nbsp;for a step-by-step setup process.

 <ol class="wp-block-list" style="list-style-type:lower-alpha;">
  <li><strong>IMPORTANT</strong>: make sure to follow step 8 for the appropriate firewall settings.</li>
 </ol>
 </li>
</ol>

<ol class="wp-block-list" start="4">
 <li>Like <a href="https://static.dmcinfo.com/latest-thinking/blog/id/10162/getting-started-with-a-beckhoff-plc-part-one--setup#Install RTE Driver">step 6</a> in the linked article, we need to install the Beckhoff Real-Time Ethernet Driver for our networked port.

 <ol class="wp-block-list" style="list-style-type:lower-alpha;">
  <li>Regardless of whether you use direct or networked ethernet communication, this driver will&nbsp;need to be installed on the appropriate ethernet port.</li>
 </ol>
 </li>
</ol>

<ol class="wp-block-list" start="5">
 <li>Navigate to&nbsp;<strong>C:\TwinCAT\3.1\System</strong>&nbsp;and run&nbsp;<strong>TcRteInstall.exe:</strong></li>
</ol>

<p class="wp-block-paragraph" style="text-align: center;"><strong><img decoding="async" alt="TcRteInstall_Location" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/TCREInstall.png"  /></strong></p>

<ol class="wp-block-list" start="6">
 <li>Install the driver onto the Networked port. For a networked connection, the IPv4 properties found in <a href="https://static.dmcinfo.com/latest-thinking/blog/id/10162/getting-started-with-a-beckhoff-plc-part-one--setup#Changing NIC Settings">step 2</a> of the linked article will need to include an appropriate IP address, subnet mask, and gateway to the local server.</li>
</ol>

<p class="wp-block-paragraph" style="text-align: center;"><img decoding="async" alt="IPv4_Properties" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/IPv4-protocol.png"  /></p>

<p class="wp-block-paragraph" style="text-align: center;"><em>Note: if you as a user also have access to this internal network through local access or a VPN, you can program the PLC from this networked port and no longer need a physical connection to the IPC.</em></p>

<ol class="wp-block-list" start="7">
 <li>With the correct configuration of your IPv4&nbsp;network properties, you should be able to discover other devices on the server.</li>
</ol>

<p class="wp-block-paragraph" style="text-align: center;"><img decoding="async" alt="IPC_Ping_Test" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Ping.png"  /></p>

<ol class="wp-block-list" start="8">
 <li>Next, we need to set the AMS NetId to partner with the expected service. This step will ensure that there are no conflicting communication paths between PLCs. At DMC&nbsp;these are typically set to the PLC IP address and extended with a .1.1, as seen below, to match the expected 6-byte TwinCAT network ID.</li>
</ol>

<p class="wp-block-paragraph" style="text-align: center;"><img decoding="async" alt="AMS_NetID_set_1" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/ams1.png"  /><img decoding="async" alt="AMS_NetID_set_2" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/ams2.png"  /></p>

<h2 class="wp-block-heading">TwinCAT XAE&nbsp;Configuration:</h2>

<p class="wp-block-paragraph">We can now migrate to the TwinCAT XAE environment and begin&nbsp;creating EAP masters through the networked ports on the IPC, as shown above or by using the EL-6601 or EL-6614 hardware options, which extend the IPCs available ethernet ports.</p>

<p class="wp-block-paragraph" style="text-align: center;"><em>Note: the EL-6652 supports Ethernet/IP communication to other PLC platforms and will be covered in a future blog. &nbsp;&nbsp;&nbsp;</em></p>

<p class="wp-block-paragraph"><strong><u>TwinCAT XAE EtherCAT Automation Protocol (EAP) Setup:</u></strong></p>

<p class="wp-block-paragraph">For this tutorial, we will be using the EAP Master that is linked to an internal IPC network port.</p>

<ol class="wp-block-list">
 <li>Begin by right-clicking on Devices in the IO tree here:</li>
</ol>

<p class="wp-block-paragraph" style="text-align: center;"><img decoding="async" alt="Add_a_EAP_Master" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/EAP1.png"  /></p>

<p class="wp-block-paragraph">&nbsp; &nbsp; &nbsp; &nbsp;2. Then, select the EAP Master:</p>

<p class="wp-block-paragraph" style="margin-left: 40px; text-align: center;"><img decoding="async" alt="EAP_Master_2" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Eap2.png"  /></p>

<p class="wp-block-paragraph">Once instantiated, the box is ready to set up publishers and subscribers. Publishers can &ldquo;publish&rdquo; or send data out across an EAP connection while subscribers will&nbsp;&ldquo;subscribe&rdquo; and listen for that data. These can be instantiated by right-clicking on the EAP master and adding a new device.</p>

<p class="wp-block-paragraph"><u><strong>Publishers:</strong></u></p>

<p class="wp-block-paragraph">There are a few ways to set up the communication bridge. At DMC, the two most common are the UDP/IP Unicast and&nbsp;the RT-Ethernet Unicast with the AMS NetId. Unless you are using multicast, it will be one box per PLC to PLC connection.</p>

<ol class="wp-block-list">
 <li>To publish with UDP, specify the Unicast destination which is the Networked IP address of the desired IPC and the default gateway hosting the server traffic.</li>
</ol>

<p class="wp-block-paragraph">&nbsp;</p>

<p class="wp-block-paragraph" style="text-align: center;"><img decoding="async" alt="UDP_Unicast" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Casting1.png"  /></p>

<p class="wp-block-paragraph" style="margin-left: 40px;">2. To publish with RT-Ethernet, set the AMS NetId of the subscriber. This requires the two networked IPCs to be on the same server and discoverable by one another.</p>

<p class="wp-block-paragraph" style="text-align: center;"><img decoding="async" alt="RT_Casting" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/RTCast2_1.png"  /></p>

<p class="wp-block-paragraph" style="margin-left: 40px;">3. Regardless of your chosen method, you can now instantiate networked variables to publish from your boxes. To do this, right click on the publisher box and select &apos;add new item&apos;. Then, configure the data you need to send.</p>

<p class="wp-block-paragraph" style="text-align: center;"><img decoding="async" alt="Insert_Network_Variable" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Network-Variable.png"  /></p>

<p class="wp-block-paragraph" style="margin-left: 40px;">4.Next, link the instantiated publisher variable data to the PLC variable you wish to send out within the outputs sub-selection on the publisher box:</p>

<p class="wp-block-paragraph" style="text-align: center;"><img decoding="async" alt="Data_Link" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Linking.png"  /></p>

<p class="wp-block-paragraph" style="margin-left: 40px;">5.Continue this process for all the variables you wish to use in EAP communication, and then activate the configuration to change the memory space.</p>

<p class="wp-block-paragraph"><u><b>Subscribers:</b></u></p>

<p class="wp-block-paragraph" style="margin-left: 40px;">1.Similar to publishers on an EAP Master, add a new item and select Network Variable Subscriber.</p>

<p class="wp-block-paragraph" style="margin-left: 40px;">2. There are a couple of options for adding subscriber variables. The easiest is to browse for computers. This requires the RT-Ethernet setup on the publisher. To do so, right click on the subscriber box and select &apos;add new item&apos;. Then, select &apos;browse for computer.&apos;</p>

<p class="wp-block-paragraph" style="text-align: center;"><img decoding="async" alt="Import_Network_Variable" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Networkvariable2.png"  /></p>

<p class="wp-block-paragraph" style="margin-left: 40px;">3. Add the appropriate dialog route for your search, and establish the connection.</p>

<p class="wp-block-paragraph" style="text-align: center;"><img decoding="async" alt="Connect_to_the_PLC" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/ConnectToPLC.png"  /></p>

<p class="wp-block-paragraph" style="margin-left: 40px;">4. After establishing a connection, the published variables will populate to the network variables list.</p>

<p class="wp-block-paragraph" style="text-align: center;"><img decoding="async" alt="Select_A_Variable" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/SelectVariable.png"  /></p>

<p class="wp-block-paragraph" style="margin-left: 40px;">5. Select the variables you wish to subscribe to, and link them to subscriber IPC inputs to use in logic. Note that the quality tag can be used as a heartbeat monitor and that a value of 0 is a successful connection. Activate the configuration and check to see if the connection is present.</p>

<p class="wp-block-paragraph" style="text-align: center;"><img decoding="async" alt="Linked_Subscriber" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/LinkedVariable.png"  /></p>

<p class="wp-block-paragraph" style="margin-left: 40px;">6. For the UDP Unicast Publisher, set up the subscriber to receive from any publisher because the publisher is providing the IPC pointing. Then, instead of browsing&nbsp;for a computer, use &apos;create a new variable,&apos; and give it the definition the publisher is providing whether that be INT, BOOL, or any other data type.</p>

<p class="wp-block-paragraph" style="margin-left: 40px;">7. Next, in the subscribe tab of the new variable, provide the expected publisher variable ID and link like in step 5. This will also come with a quality check for the connection state.</p>

<p class="wp-block-paragraph">Now that the publisher and subscriber have achieved a connection, the networked variables and connection quality are available to the subscriber PLC to use in any desired logic.</p>

<p class="wp-block-paragraph"><strong>Learn more about DMC&apos;s <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/plc-programming/beckhoff-and-twincat-3-programming">Beckhoff and TwinCAT Programming</a> expertise and <a href="https://static.dmcinfo.com/contact">contact us</a> for your next project.&nbsp;</strong></p>
<p>The post <a href="https://static.dmcinfo.com/blog/17760/beckhoff-plc-to-plc-communication-using-eap-a-starter-guide/">Beckhoff PLC to PLC Communication Using EAP &#8211;  A Starter Guide</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Getting Started with OPC UA in Beckhoff TwinCAT 3</title>
		<link>https://static.dmcinfo.com/blog/17976/getting-started-with-opc-ua-in-beckhoff-twincat-3/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Thu, 15 Dec 2022 10:15:37 +0000</pubDate>
				<category><![CDATA[Beckhoff PLC]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[PLC]]></category>
		<category><![CDATA[Beckhoff]]></category>
		<category><![CDATA[OPC UA]]></category>
		<category><![CDATA[TwinCAT]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/17976/getting-started-with-opc-ua-in-beckhoff-twincat-3/</guid>

					<description><![CDATA[<p>Table of Contents 1. Introduction OPC UA (short for Open Platform Communications Unified Architecture) is a client/server technology used for data exchange in industrial applications, commonly used for machine-to-machine and&#160;PC-to-machine communication. Because of its versatility, OPC UA was adopted in a variety of industries such as the automotive, food and beverage, gas and oil, energy [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/17976/getting-started-with-opc-ua-in-beckhoff-twincat-3/">Getting Started with OPC UA in Beckhoff TwinCAT 3</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading" id="h-table-of-contents">Table of Contents</h2>



<ol class="wp-block-list">
<li><a href="#h-introduction">Introduction</a></li>



<li><a href="#h-2-things-you-ll-need-to-download-and-install">Things You’ll Need to Download and Install</a></li>



<li><a href="#h-3-step-by-step-procedure">Step by Step Procedure</a></li>



<li><a href="#h-4-notes-on-security">Notes on Security</a></li>
</ol>



<h2 class="wp-block-heading" id="h-1-introduction">1. Introduction</h2>



<p class="wp-block-paragraph">OPC UA (short for Open Platform Communications Unified Architecture) is a client/server technology used for data exchange in industrial applications, commonly used for machine-to-machine and&nbsp;PC-to-machine communication. Because of its versatility, OPC UA was adopted in a variety of industries such as the automotive, food and beverage, gas and oil, energy and utilities, and packaging industries. It can also be used in applications ranging from embedded components to cloud servers.</p>



<p class="wp-block-paragraph">Setting up an OPC UA server in Beckhoff is very simple and can allow you to connect your Beckhoff project to other software, like Ignition and other SCADA platforms. This guide will teach you how to set up an OPC UA server on your programming PC or your Beckhoff IPC and set up your TwinCAT project to display tags from that server.</p>



<p class="wp-block-paragraph">For this demonstration, we will be connecting to an OPC UA server on our local Windows 10 machine, but the process should be similar for connecting to an OPC UA server on a remote machine like a Beckhoff IPC, with just a few additional steps to allow that server to be accessed on whichever network you’re using.</p>



<h2 class="wp-block-heading" id="h-2-things-you-ll-need-to-download-and-install">2. Things You’ll Need to Download and Install</h2>



<h3 class="wp-block-heading" id="h-2-1-twincat">2.1 TwinCAT</h3>



<ul class="wp-block-list">
<li><strong>2.1.1. TwinCAT XAE Shell<br></strong>This is where the PLC will be set up, code will be written, and other settings will be chosen. If you’re looking for this guide, you most likely have TwinCAT installed. Otherwise, you can download it from <a href="https://www.beckhoff.com/en-us/support/download-finder/" target="_blank" rel="noreferrer noopener">Beckhoff’s Website</a>.</li>



<li><strong>2.1.2. TwinCAT XAR Runtime<br></strong>XAR is used to run TwinCAT on a Beckhoff IPC, and we&#8217;ll need to install it on the end PLC if we&#8217;re not installing XAE on that machine. This means that this download is only necessary if you intend to host your OPC server on a different machine than your programming PC. You will still need to get TwinCAT XAE on your programming PC. XAR can also be downloaded from <a href="https://www.beckhoff.com/en-us/support/download-finder/" target="_blank" rel="noreferrer noopener">Beckhoff’s Website</a>.</li>
</ul>



<h3 class="wp-block-heading" id="h-2-2-nbsp-tf6100-twincat-3-opc-ua-server-and-configurator">2.2.&nbsp;TF6100 | TwinCAT 3 OPC UA Server and Configurator</h3>



<p class="wp-block-paragraph">These are necessary to actually create the OPC UA Server and initialize it. The OPC UA Server is the actual runtime program, while the OPC UA Configurator is only needed to initialize the server. TF6100 includes two other products that are not required to set up the server (OPC UA Gateway and OPC UA Client). They&nbsp;won’t be used in this guide, but can be installed to facilitate the use of the OPC UA server, depending on the application. These applications need a license, but they do have a trial you can activate from TwinCAT. These applications can also be found on the <a href="https://www.beckhoff.com/en-us/products/automation/twincat/" target="_blank" rel="noreferrer noopener">Beckhoff Website</a>.</p>



<h3 class="wp-block-heading" id="h-2-3-any-opc-ua-tester">2.3 Any OPC UA Tester</h3>



<p class="wp-block-paragraph">This is useful to test that our tags created in TwinCAT are actually findable in the OPC Server. You can use UaExpert, Ignition, or Beckhoff’s OPC UA Client. Anything that can connect to an OPC Server and see its contents will be enough.</p>



<h2 class="wp-block-heading" id="h-3-step-by-step-procedure">3. Step by Step Procedure</h2>



<p class="wp-block-paragraph">First, install the above software in the following locations:</p>



<p class="wp-block-paragraph">Programming Computer: the computer you&#8217;ll do your programming on.</p>



<ul class="wp-block-list">
<li>TwinCAT XAE</li>



<li>OPC UA Configurator</li>



<li>OPC UA Test Client (optional)</li>
</ul>



<p class="wp-block-paragraph">Runtime Device: the device you&#8217;ll be running the OPC UA server on. It could be your programming computer (for testing) or a Beckhoff IPC.</p>



<ul class="wp-block-list">
<li>TwinCAT XAR (if this runtime device does not have TwinCAT XAE installed on it)</li>



<li>OPC UA Server</li>



<li>OPC UA Test Client (optional)</li>
</ul>



<p class="wp-block-paragraph">Next, open TwinCAT XAE, and either load an existing project with a PLC or start a new TwinCAT Project. Under SYSTEM, double click License. If you have a license for the TF6100, it will be shown as in the picture below. </p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/1_License_for_the_TF6100.png" alt="License for the TF6100"/></figure>



<p class="wp-block-paragraph">If you don’t have a license, you can go to the <strong>Manage Licenses</strong> tab and check the CPU license checkmark for the TF6100. Go back to the <strong>Order information</strong> tab and select <strong>7-Day Trial License.</strong></p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2_Manage_Licenses_1.png" alt="Manage Liceses"/></figure>



<p class="wp-block-paragraph">Once this is done, save your project, close TwinCAT, and then <strong>RESTART YOUR PC/VM. The OPC UA Server software won’t work until after a restart. </strong>You can tell that the OPC UA server is running by an icon in the bottom right of the Windows tray.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/3_OPC_UA_Server_is_running_icon.png" alt="OPC UA Server is running icon"/></figure>



<p class="wp-block-paragraph">Once you make sure the OPC UA Server is running, you will need to initialize the server. Open the OPC UA configurator and click <strong>Edit&gt;Get Endpoints</strong>, followed by <strong>Add</strong>, once the configurator has found the endpoints<strong>.</strong> If you’re performing this step from the same machine as the server, you can use <strong>opc.tcp:https://static.dmcinfo.com/</strong> as the server URL.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/4_TwinCAT_OPC_UA_Configurator_Edit.png" alt="TwinCAT OPC UA Configurator Edit"/></figure>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/5_Configured_TwinCAT_OPC_UA_Servers.png" alt="Configured TwinCAT OPC UA Servers"/></figure>



<p class="wp-block-paragraph">Once you add the server, it should look something like this. If the configurator can’t find the endpoints, you should verify that&nbsp;the server is running by checking the Windows tray bar.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/6_Server_is_running_Windows_tray_bar.png" alt="Server is running Windows tray bar"/></figure>



<p class="wp-block-paragraph">Go back to the main page of the configurator and click&nbsp;<b data-stringify-type="bold">Connect</b>. This should cause a pop-up to choose an Operating system user account for the server. For now, fill in the OS credentials for your IPC or VM. You’ll be able to add more users later. Once you fill those out, the server should initialize. Click&nbsp;<b data-stringify-type="bold">Connect</b>&nbsp;once more to make sure you can connect to the server</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/7_Server_initialization.png" alt="Server initialization"/></figure>



<p class="wp-block-paragraph">Next, open TwinCAT again, right-click your PLC project, and check the “Autostart Boot Project.” This will avoid some pop-ups and ensure the PLC runs smoothly once it starts.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/8_Autostart_Boot_Project.png" alt="Autostart Boot Project"/></figure>



<p class="wp-block-paragraph">Next, double click the PLC project (Untitled1 in the example) and go to the “Settings” tab. <strong><u>CHECK THE “TMC FILE” OPTION</u>. </strong>TwinCAT Module Class (.tmc files) contains the symbol information necessary for the our tags to be accessible via the OPC Server.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/9_TMC_File_option.png" alt="TMC File options"/></figure>



<p class="wp-block-paragraph">Next, inside your MAIN program, make the changes you want. If you just want to test the OPC UA server, you can test it using the program below, which should flip the test variable from TRUE to FALSE every second.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Pascal</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>PROGRAM MAIN
VAR
	{attribute 'OPC.UA.DA' := '1'} 
	hi:BOOL;
	timer: ton;
END_VAR</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">PROGRAM</span><span style="color: #D4D4D4"> MAIN</span></span>
<span class="line"><span style="color: #569CD6">VAR</span></span>
<span class="line"><span style="color: #D4D4D4">	</span><span style="color: #6A9955">{attribute &apos;OPC.UA.DA&apos; := &apos;1&apos;}</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">	hi:BOOL;</span></span>
<span class="line"><span style="color: #D4D4D4">	timer: ton;</span></span>
<span class="line"><span style="color: #D4D4D4">END_VAR</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Pascal</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>timer(IN := NOT timer.Q, PT := T#1S) ;
IF timer.Q THEN
	hi := NOT hi;
END_IF</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">timer(</span><span style="color: #569CD6">IN</span><span style="color: #D4D4D4"> := </span><span style="color: #569CD6">NOT</span><span style="color: #D4D4D4"> timer.Q, PT := T</span><span style="color: #CE9178">#1</span><span style="color: #D4D4D4">S) ;</span></span>
<span class="line"><span style="color: #569CD6">IF</span><span style="color: #D4D4D4"> timer.Q </span><span style="color: #569CD6">THEN</span></span>
<span class="line"><span style="color: #D4D4D4">	hi := </span><span style="color: #569CD6">NOT</span><span style="color: #D4D4D4"> hi;</span></span>
<span class="line"><span style="color: #D4D4D4">END_IF</span></span></code></pre></div>



<p class="wp-block-paragraph">Notice the line <u><strong>{attribute ‘OPC.UA.DA’ := ‘1’}</strong></u><strong>. </strong><strong>This line is necessary to expose any variables to the OPC UA Server. </strong>If you would like to specify read/write permissions, you can use the following line: <strong>{attribute &#8216;OPC.UA.DA.Access&#8217; := &#8216;x&#8217;}</strong>, where x = 1 will be read-only, x = 2 will be write access only, and x = 3 will be read and write access (the default option if this attribute is not specified).</p>



<p class="wp-block-paragraph">Once you’re done writing your code, <strong>activate the configuration</strong> with the button shown in the image below. Your project/tags will not show up on the server otherwise. You’ll want to activate the configuration every time you add new tags that are exposed to OPC UA. This will both download your code and restart the OPC UA Server, which must be done for new tags to show up. Alternatively, you can download/make online changes to your code and restart the OPC UA server using the server’s Windows tray icon.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/10_activate_the_configuration_button.png" alt="Activate the configuration button"/></figure>



<p class="wp-block-paragraph">Once this is done, login, and run your code.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/11_login.png" alt="Login"/></figure>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/12_run_the_code.png" alt="Run the code"/></figure>



<p class="wp-block-paragraph">After this, the server should be up and running, and your tags should be visible. If you are using UaExpert (or your program of choice) on the same machine the server is running, you can connect to it using <strong>opc.tcp:https://static.dmcinfo.com/ </strong>as the endpoint URL. If you’re prompted for credentials, use the ones you chose when initializing the server. After that, click <strong>connect</strong> to verify that your tags show up in the server.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/13_14.png" alt="Add Server Hi"/></figure>



<p class="wp-block-paragraph">If you need to access your tags from a different device in your network (for example, if you’re hosting your OPC Server on your IPC, but would like to browse tags via your programming PC), you’ll need to first create a firewall rule to allow for inbound traffic through port 4840 on the device hosting the OPC server. 4840 is the default port for this, but if you’ve configured another port for your OPC UA server to use, you’ll have to open that port instead. Go to <strong>Settings&gt;Windows Security&gt;Firewall &amp; Network Settings&gt;Advanced Settings&gt;Inbound Rules</strong> and add a rule like the images below.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/15_Port.png" alt="Port"/></figure>



<p class="wp-block-paragraph">Select <strong>port</strong> and then <strong>TCP</strong>, add local port <strong>4840,</strong> allow connection, and give it a name.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/16_TCP.png" alt="TCP"/></figure>



<p class="wp-block-paragraph">Once this is done, open UaExpert (or your program of choice) and add a server using <strong>opc.tcp://<em>*OPC Host IP Address*</em>:4840 </strong>as the endpoint URL; the tags should be visible. If this is not the case, restart the computer hosting the server.</p>



<h2 class="wp-block-heading" id="h-4-notes-on-security">4. Notes on Security</h2>



<p class="wp-block-paragraph">This section will briefly touch on how to alter the security settings of your OPC UA server — including adding/removing users, editing current user passwords, changing security policies, and choosing the desired server port. This will all be done through the TF6100 TwinCAT OPC UA Configurator, the same application you used to the initialize server.</p>



<p class="wp-block-paragraph">Open the configurator and select <strong>Edit </strong>on the toolbar.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/17_Edit_1.png" alt="Edit"/></figure>



<p class="wp-block-paragraph">Click <strong>Get Endpoints</strong> followed by <strong>Add</strong>, which should add your server to the list. The result should look something like this</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/18_Get_Endpoints_and_Add.png" alt="Get Endpoints and Add"/></figure>



<p class="wp-block-paragraph">Double-click the name of the server to configure the server connection. Alter the information in the setting to match the ones at your server. If you didn’t change any of these when setting up the server, just fill in your identity (these are the credentials you chose when initializing the server). Click <strong>OK</strong>.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/19_OK.png" alt="OK"/></figure>



<p class="wp-block-paragraph">Click <strong>Connect</strong>. This will prompt a user authentication pop-up. Fill in the password you chose when you initialized the server.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/20_user_authentication_password.png" alt="User authentication password"/></figure>



<p class="wp-block-paragraph">Now you should be connected to the server. If the connection fails, double-check that&nbsp;the OPC Server is running by checking for its icon in the Windows tray. If you get an error similar to [BadUserAcessDenied] or [BadIdentityAcessDenied], that means your credentials are not correct.</p>



<p class="wp-block-paragraph">If you intend to add, remove, or edit users, click on the security tab, and then click the <strong>Open From Target</strong> Icon on the toolbar. Your screen should look something like the image below. Right-click on the users box, and select from <strong>Add</strong>, <strong>Remove,</strong> or <strong>Edit</strong>. In this example, we will be adding a new user.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/21_adding_a_new_user_1.png" alt="Adding a new user"/></figure>



<p class="wp-block-paragraph">A user detail pop-up should appear. On this pop-up, you can select the authentication provider from Server (choose any UserName and Password), OS (matches a user and password from your computer), and <strong>Anonymous</strong> (provides no credentials). When applicable, you can also select the username, password, and the member groups: which this user is part of.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/22_user_details.png" alt="User details"/></figure>



<p class="wp-block-paragraph">Once you add the users you desire, click <strong>Activate on Target, </strong>and the new user should be added to the server.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/23_Activate_on_Target.png" alt="Activate on Target"/></figure>



<p class="wp-block-paragraph">If you want to change the server port or the security policy of your server, click on the <strong>Server Settings</strong> tab, where both options should be visible, like the image below. Make sure to <strong>Activate on Target </strong>once you finish making your changes.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/24_TwinCAT_OPC_UA_Configurator.png" alt="TwinCAT OPC UA Configurator"/></figure>



<p class="wp-block-paragraph"><strong>Read more about&nbsp;<a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/plc-programming/beckhoff-and-twincat-3-programming/">DMC’s Beckhoff and TwinCAT 3&nbsp;Programming</a>, and <a href="https://static.dmcinfo.com/contact/">contact us</a> today for your next project!</strong></p>
<p>The post <a href="https://static.dmcinfo.com/blog/17976/getting-started-with-opc-ua-in-beckhoff-twincat-3/">Getting Started with OPC UA in Beckhoff TwinCAT 3</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>TwinCAT Project Variants</title>
		<link>https://static.dmcinfo.com/blog/18781/twincat-project-variants/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Tue, 01 Feb 2022 17:45:00 +0000</pubDate>
				<category><![CDATA[Beckhoff PLC]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[PLC]]></category>
		<category><![CDATA[Project Variants]]></category>
		<category><![CDATA[TwinCAT]]></category>
		<category><![CDATA[Variants]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/18781/twincat-project-variants/</guid>

					<description><![CDATA[<p>Introducing TwinCAT Project Variants! Variants are available from build 4024 onward and allow you to modify hardware configuration and even run different code based on different versions of the same project. You can quickly toggle between these versions using a dropdown in TCXAE. This article discusses the basics of configuration/capabilities of project variants and some [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/18781/twincat-project-variants/">TwinCAT Project Variants</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">Introducing <a href="https://infosys.beckhoff.com/english.php?content=../content/1033/variant_management/index.html&amp;id=640168702518993771" target="_blank">TwinCAT Project Variants</a>! Variants are available from build 4024 onward and allow you to modify hardware configuration and even run different code based on different versions of the same project. You can quickly toggle between these versions using a dropdown in TCXAE.</p>

<p class="wp-block-paragraph">This article discusses the basics of configuration/capabilities of project variants and some example uses for them.</p>

<h2 class="wp-block-heading"><u><a id="Table of Contents" name="Table of Contents"></a>Table of Contents:</u></h2>

<ol class="wp-block-list">
 <li><a href="#Why Use Variants?">Why Use Variants?</a></li>
 <li><a href="#Setup">Setup</a></li>
 <li><a href="#Using Variants to Run Different Code">Using Variants to Run Different Code</a></li>
 <li><a href="#Simulating Axes with Variants">Simulating Axes with&nbsp;Variants&nbsp;</a></li>
 <li><a href="#Using Variants for Multiple Similar Machines">Using&nbsp;Variants for Multiple Similar Machines&nbsp;</a></li>
 <li><a href="#Gotchas">Gotchas&nbsp;</a></li>
 <li><a href="#Further Reference">Further Reference</a></li>
</ol>

<p class="wp-block-paragraph">&nbsp;</p>

<h2 class="wp-block-heading"><u><a id="Why Use Variants?" name="Why Use Variants?"></a>Why Use Variants?</u></h2>

<p class="wp-block-paragraph"><em><a href="#Table of Contents">Back to Table of Contents</a></em></p>

<p class="wp-block-paragraph">Why might I want to use variants, you ask?</p>

<p class="wp-block-paragraph" style="margin-left: 40px;"><strong>1.&nbsp;&nbsp; &nbsp;Facilitating Simulation</strong><br />
While you might want to prepare for deploying your code by mapping PLC inputs/outputs to the correct hardware, you also might want to disable hardware or even change mappings so you can simulate your software locally. Project variants allow you to enable and disable hardware components in your TwinCAT project and adjust variable mapping. By using them, you can easily switch between a deployment configuration and a simulation configuration.</p>

<p class="wp-block-paragraph" style="margin-left: 40px;"><strong>2.&nbsp;&nbsp; &nbsp;Parallel Online/Offline Development</strong><br />
Sometimes at DMC we run into situations where, in order to meet a project&rsquo;s deadlines, we must begin commissioning a machine while offline development of the software is still occurring. Our engineers might need to make changes to the hardware configuration or code so that they can simulate the PLC software on their own machines. However, merging updates back into branches that may be deployed to live machines can subsequently get messy. Engineers might forget to remove those changes made for simulation, leading to unnecessary effort reverting those changes for the live system. Using variants for simulation or different testing configurations can make this a breeze.</p>

<p class="wp-block-paragraph" style="margin-left: 40px;"><strong>3.&nbsp;&nbsp; &nbsp;Maintaining Multiple Similar Machines</strong><br />
Often different machines might use the same codebase but vary slightly, with extra options included or slightly different hardware configurations. Project variants can be used to manage the different types of a certain machine without having to create separate projects for different hardware configurations.</p>

<p class="wp-block-paragraph">&nbsp;</p>

<h2 class="wp-block-heading"><u><a id="Setup" name="Setup"></a>Setup</u></h2>

<p class="wp-block-paragraph"><em><a href="#Table of Contents">Back to Table of Contents</a></em></p>

<p class="wp-block-paragraph">To use variants, enable the toolbar with <strong>View &gt; Toolbars &gt; TwinCAT XAE Project Variants.</strong></p>

<p class="wp-block-paragraph"><strong><figure class="wp-block-image"><img decoding="async" alt="TwinCAT project variants interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_1.png"  /></figure></strong></p>

<p class="wp-block-paragraph">This tool bar consists of the <strong>Project Variant Manager</strong> icon and the dropdown to select the active variant. To add new variants/groups, click on the <strong>Project Variant Manager</strong> icon.&nbsp;</p>

<p class="wp-block-paragraph"><strong><figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Project_Variant_Manager_Icon_1.png"  /></figure></strong></p>

<p class="wp-block-paragraph">Simply type a name in the popup to add a new variant.</p>

<p class="wp-block-paragraph"><strong><figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_2.png"  /></figure></strong></p>

<p class="wp-block-paragraph">There is also a group feature, which allows you to place variants into groups. Define groups in the same way and select which variants should be included in which groups.</p>

<p class="wp-block-paragraph"><strong><figure class="wp-block-image"><img decoding="async" alt="TwinCAT project variants interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_3.png"  /></figure></strong></p>

<p class="wp-block-paragraph">This grouping feature can be very powerful, as it allows you to make edits that will propagate to all the variants in a group, instead of having to make those edits across several variants individually. Variants can also belong to multiple groups.</p>

<p class="wp-block-paragraph">The dropdown list should now be populated with variants to choose from. There is also the<strong> [All] </strong>option, which will allow you to make edits that will propagate to all variants in the project.</p>

<figure class="wp-block-image"><img decoding="async" alt="TwinCAT project variants interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_4.png"  /></figure>

<p class="wp-block-paragraph">Making variants alone will not necessarily make them useful within the project. You must also define what aspects of your project you wish to be modified by the variants.&nbsp;<br />
If you click on an item in the Solution Explorer, you should see a <strong>Project Variants</strong> section in the <strong>Properties</strong> window <strong>(View &gt; Properties Window</strong> if it&rsquo;s not already open). Each item in the solution tree may have different options for what can change based on the currently active project variant.</p>

<p class="wp-block-paragraph">For example, here I have two EtherCAT masters for the different modules of my machine. I have the option of setting the <strong>Address Info</strong>, <strong>Disable</strong>, and <strong>Parameter</strong> to be dependent on project variants. Here I&rsquo;ve chosen to control whether these components are disabled based on the active project variant by setting the <strong>Disable </strong>option to <strong>True</strong>. I&rsquo;ve prevented the other available aspects of the components from changing based on the active variant by setting them to <strong>False</strong>.</p>

<p class="wp-block-paragraph"><strong><figure class="wp-block-image"><img decoding="async" alt="TwinCAT project variants interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_5.png"  /></figure></strong><br />
&nbsp;<br />
Once an item in the solution explorer tree has been configured to change based on variants, a little blue triangle will appear in the upper right corner of the icon . This can be a helpful way to tell what has been configured for variants in your project.</p>

<p class="wp-block-paragraph"><strong><figure class="wp-block-image"><img decoding="async" alt="Twincat Project Variants Interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_6_1.png"  /></figure></strong><br />
&nbsp;<br />
As another example, I can choose if <strong>Disable </strong>and <strong>Mapping</strong> will be variant specific for an EK1100 on the module. Disabling is already variant specific in the parent component (EtherCAT Master &ldquo;ModuleA&rdquo;), so I don&rsquo;t need to&nbsp;do that here. But allowing mappings to change based on variant might be useful, as it gives me the ability map different PLC variables to different hardware based on the currently active variant.</p>

<p class="wp-block-paragraph"><strong><figure class="wp-block-image"><img decoding="async" alt="Twincat Project Variants Interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_7_1.png"  /></figure></strong></p>

<p class="wp-block-paragraph">Now that we&rsquo;ve set up these items, we simply need to make the changes we want for each variant while that variant is selected. <span class="marker"><strong>This is important &ndash; make sure you have the correct variant selected! </strong></span>If not, you could be inadvertently making changes to the wrong variant, or worse, a group of wrong variants.</p>

<p class="wp-block-paragraph">In this example, I can choose four variants:</p>

<p class="wp-block-paragraph"><strong>SimulateAllModules</strong> &ndash; Everything is simulated. This allows easy testing on engineers&rsquo; laptops for offline development. Notice how EtherCAT masters ModuleA and ModuleB are both disabled.</p>

<figure class="wp-block-image"><img decoding="async" alt="Twincat Project Variants Interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_8_1.png"  /></figure>

<p class="wp-block-paragraph"><strong>SimulateModuleA</strong> &ndash; If commissioning is occurring but hardware isn&rsquo;t ready for Module A yet, we can enable the real hardware for Module B and still simulate Module A. Notice how ModuleA is disabled, but ModuleB is not.</p>

<figure class="wp-block-image"><img decoding="async" alt="Twincat Project Variants Interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_9_1.png"  /></figure>

<p class="wp-block-paragraph"><strong>SimulateModuleB</strong> &ndash; For situations similar to &ldquo;SimulateModuleA&rdquo;, but with ModuleB disabled and ModuleA enabled.</p>

<p class="wp-block-paragraph"><strong><figure class="wp-block-image"><img decoding="async" alt="TwinCAT project variants interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_10_1.png"  /></figure></strong></p>

<p class="wp-block-paragraph"><strong>Production</strong> &ndash; Full machine hardware is available, nothing is simulated. All hardware enabled.</p>

<p class="wp-block-paragraph"><strong><figure class="wp-block-image"><img decoding="async" alt="TwinCAT project variants interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_11_1.png"  /></figure></strong></p>

<p class="wp-block-paragraph">Switching between variants is as simple as selecting a new option in the dropdown. This can be a huge time saver when commissioning the machine if you need to optionally disable hardware components. But it also allows us to quickly switch between our simulation environment for offline development and our production environment for commissioning/onsite troubleshooting purposes. Also, changes made in the hardware configuration for simulation will not affect hardware configuration in the production environment &ndash; freeing offline developers from worrying about problems with merging updated code into deployment branches.</p>

<p class="wp-block-paragraph">&nbsp;</p>

<h2 class="wp-block-heading"><u><a id="Using Variants to Run Different Code" name="Using Variants to Run Different Code"></a>Using Variants to Run Different Code</u></h2>

<p class="wp-block-paragraph"><em><a href="#Table of Contents">Back to Table of Contents</a></em></p>

<p class="wp-block-paragraph"><strong>Variants do not affect project code components</strong> &ndash; at least not by changing the code that is present. This is generally a good thing, as it reduces confusion in the codebase. But we &nbsp;still have options to allow our currently active variant to affect what code is running by using compiler defines and <a href="https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_plc_intro/2529795979.html&amp;id=" target="_blank">conditional pragmas</a>.</p>

<p class="wp-block-paragraph">To set this up, enable <strong>Defines</strong> in the PLC project and enable <strong>Implicit</strong> defines as shown here:</p>

<p class="wp-block-paragraph"><strong><figure class="wp-block-image"><img decoding="async" alt="TwinCAT project variants interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_12_1.png"  /></figure></strong></p>

<p class="wp-block-paragraph">These settings will define identifiers for the compiler with the name of the currently active variant and the group to which that variant belongs. The compiler can then use these identifiers to choose whether or not to declare variables or execute code.</p>

<p class="wp-block-paragraph">Here is an example of using compiler defines in the implementation section.</p>

<figure class="wp-block-image"><img decoding="async" alt="Twincat Project Variants Interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_13_1.png"  /></figure>

<p class="wp-block-paragraph">Here, the <strong>Simulate</strong> methods of each machine module function block only run if an identifier is defined for a project variant in which that module is simulated. In other words, if the SimulateModuleA project variant is currently active, then an identifier with the name of &ldquo;SimulateModuleA&rdquo; is implicitly defined. Using the conditional pragma,<strong> (defined SimulateModuleA) </strong>evaluates to <strong>TRUE</strong>, and we execute Module A&rsquo;s simulation method.</p>

<p class="wp-block-paragraph">One potential problem with this approach is that if the conditional pragmas are used as shown here, it may be difficult to tell what is being simulated. When I go online to monitor the PLC, this is all that I see:</p>

<p class="wp-block-paragraph"><figure class="wp-block-image"><img decoding="async" alt="Twincat Project Variants Interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_14_1.png"  /></figure><br />
&nbsp;<br />
It&rsquo;s impossible to tell from this view what is being simulated. A more readable solution &nbsp;would be to use conditional pragmas in the declaration section, as in the following example.<br />
Here I have defined a global variable list with a Boolean variable for simulating each module. If the proper project variant identifier is defined, then the Boolean will be set to true, and simulation will occur. Otherwise, it will be defined as false, and simulation will not occur.</p>

<p class="wp-block-paragraph"><figure class="wp-block-image"><img decoding="async" alt="TwinCAT project variants interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_15_1.png"  /></figure><br />
&nbsp;<br />
Now with some slight refactoring of the implementation section, it is very clear which modules are being simulated.</p>

<figure class="wp-block-image"><img decoding="async" alt="Twincat Project Variants Interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_16_1.png"  /></figure>

<p class="wp-block-paragraph">Using these compiler defines gives us great flexibility in what code we run based on which project variant is selected. Of course, to paraphrase a popular neighborhood hero&rsquo;s uncle: with great flexibility comes great responsibility. Misuse or overuse of compiler defines and conditional pragmas can complicate a codebase or make it difficult to monitor. We&rsquo;re trying to make our lives easier with project variants, not harder, so keep this in mind!</p>

<p class="wp-block-paragraph">&nbsp;</p>

<h2 class="wp-block-heading"><u><a id="Simulating Axes with Variants" name="Simulating Axes with Variants"></a>Simulating Axes with&nbsp;Variants</u></h2>

<p class="wp-block-paragraph"><em><a href="#Table of Contents">Back to Table of Contents</a></em></p>

<p class="wp-block-paragraph"><a href="https://infosys.beckhoff.com/english.php?content=../content/1033/tf50x0_tc3_nc_ptp/2834717323.html&amp;id=8250271195349757571" target="_blank">Simulating axes in TwinCAT</a> is incredibly easy, and variants can make the process even more seamless.</p>

<p class="wp-block-paragraph">To set up, add axes to your hardware configuration. Set the mapping to be variant dependent.</p>

<p class="wp-block-paragraph"><figure class="wp-block-image"><img decoding="async" alt="TwinCAT project variants interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_17_1.png"  /></figure><br />
&emsp;<br />
For the corresponding axis in <strong>MOTION</strong>, set the mapping to be variant dependent also.</p>

<figure class="wp-block-image"><img decoding="async" alt="TwinCAT project variants interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_18_1.png"  /></figure>

<p class="wp-block-paragraph">Now, open the axis settings tab in <strong>MOTION</strong>. For <strong>ALL</strong> variants, link the axis to the corresponding PLC axis reference instance.</p>

<p class="wp-block-paragraph"><figure class="wp-block-image"><img decoding="async" alt="TwinCAT project variants interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_19_1.png"  /></figure><br />
&emsp;<br />
Now, for all variants or groups of variants for which the axis will be simulated, remove the link to I/O and make sure the Axis Type is &ldquo;Standard (Mapping via Encoder and Drive)&rdquo;.</p>

<figure class="wp-block-image"><img decoding="async" alt="TwinCAT project variants interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_20.png"  /></figure>

<p class="wp-block-paragraph">Finally, for all variants or groups of variants for which the axis will not be simulated, make sure the axis is still linked to the proper IO and the axis type is correct.</p>

<p class="wp-block-paragraph"><strong><figure class="wp-block-image"><img decoding="async" alt="Twincat Project Variants Interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_21_1.png"  /></figure></strong></p>

<p class="wp-block-paragraph">And that&rsquo;s it! Now switching variants will also switch your axis to a simulated axis or not, based on whether or not the axis is linked to IO in the selected variant. Simulated axes can be very helpful for testing motion control logic without the actual hardware.</p>

<p class="wp-block-paragraph"><span style="font-size:12px;"><strong><figure class="wp-block-image"><img decoding="async" alt="Twincat Project Variants Interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_22_1.png"  /></figure></strong></span><br />
&emsp;<br />
Another benefit of project variants and TwinCAT motion is the ability to adjust parameters. Increasing the limits for basic motion parameters (velocity, acceleration, jerk) by orders of magnitude allow for axes in simulation to be run much faster than waiting for the axis with its real limits to complete a specific motion command. This is particularly useful when performing unit tests and axes need to complete several point-to-point movements that would otherwise take a significant amount of time. An example of this follows.</p>

<h2 class="wp-block-heading"><span style="font-size:12px;"><strong><figure class="wp-block-image"><img decoding="async" alt="Twincat Project Variants Interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_23_1.png"  /></figure></strong></span></h2>

<h2 class="wp-block-heading"><span style="font-size:12px;"><strong><figure class="wp-block-image"><img decoding="async" alt="Twincat Project Variants Interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_24_1.png"  /></figure></strong></span></h2>

<p class="wp-block-paragraph"><strong><figure class="wp-block-image"><img decoding="async" alt="Twincat Project Variants Interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_25_1.png"  /></figure></strong></p>

<p class="wp-block-paragraph">&nbsp;</p>

<h2 class="wp-block-heading"><u><a id="Using Variants for Multiple Similar Machines" name="Using Variants for Multiple Similar Machines"></a>Using&nbsp;Variants for Multiple Similar Machines</u></h2>

<p class="wp-block-paragraph"><em><a href="#Table of Contents">Back to Table of Contents</a></em></p>

<p class="wp-block-paragraph">Oftentimes controls engineers run into situations with multiple machines that use the same codebase, but only vary slightly &ndash; in hardware configuration or code.</p>

<p class="wp-block-paragraph">There are a few ways to manage a project like this in TwinCAT:</p>

<p class="wp-block-paragraph" style="margin-left: 40px;"><strong>1.&nbsp;&nbsp; &nbsp;Maintain separate repositories or branches for the different machines.</strong><br />
This is definitely not the ideal way to approach this situation. Imagine if you needed to make a change that applies to all the different machine types. You&rsquo;d need to add that change to every single repository or branch separately! It&rsquo;s a recipe for making mistakes. This approach would probably only be the best choice if the machines vary significantly.<br />
<strong>2.&nbsp;&nbsp; &nbsp;Have multiple TwinCAT XAE projects with different hardware configurations that all reference a single PLC project.</strong><br />
This works pretty well, and DMC has done this in the past. The downside to this approach is that to switch to a different machine type, you need to open up an entirely separate solution, which is time consuming.<br />
<strong>3.&nbsp;&nbsp; &nbsp;Use project variants</strong>.<br />
The advantage of the project variant approach is that the different machine configurations are stored in one solution. Switching between them is as easy as selecting an option in a dropdown.</p>

<p class="wp-block-paragraph">To illustrate this use of project variants, we&rsquo;ll use a basic example. Let&rsquo;s say Machine Type 1 has a sensor wired to a different location than on Machine Type 2.<br />
To set this up, we&rsquo;ll enable mapping on the IO card(s) to be project variant dependent.</p>

<figure class="wp-block-image"><img decoding="async" alt="Twincat Project Variants Interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_26_1.png"  /></figure>

<p class="wp-block-paragraph">We will also make mapping for the PLC instance project variant dependent.</p>

<p class="wp-block-paragraph"><strong><figure class="wp-block-image"><img decoding="async" alt="Twincat Project Variants Interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_27_1.png"  /></figure></strong></p>

<p class="wp-block-paragraph">&nbsp;Now, we simply need to select each project variant and map the PLC input to the appropriate hardware for that variant.<br />
&emsp;<br />
Machine Type 1:</p>

<p class="wp-block-paragraph"><figure class="wp-block-image"><img decoding="async" alt="TwinCAT project variants interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_28_1.png"  /></figure><br />
&emsp;<br />
Machine Type 2:</p>

<figure class="wp-block-image"><img decoding="async" alt="TwinCAT project variants interface" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Twincat_3_Project_Variants_29_1.png"  /></figure>

<p class="wp-block-paragraph">This example is pretty basic, but the concept can be extended all the way up to fully separate EtherCAT masters with very different hardware configurations for each machine configuration. However, this brings back the discussion of responsibility in the use of project variants &ndash; at some point, it might just make more sense to create a new project if one machine differs vastly from another. What should be done with project variants and what should be done with a new project is at the software architect&rsquo;s discretion.</p>

<p class="wp-block-paragraph">If you&rsquo;ve used project variants for multiple similar machines, I&rsquo;d love to hear your perspective on the positives and negatives of the experience. Please leave a comment below!</p>

<p class="wp-block-paragraph">&nbsp;</p>

<h2 class="wp-block-heading"><u><a id="Gotchas" name="Gotchas"></a>Gotchas</u></h2>

<p class="wp-block-paragraph"><em><a href="#Table of Contents">Back to Table of Contents</a></em></p>

<p class="wp-block-paragraph">Project variants are incredibly useful, but like any feature that introduces complication, there are a few things to look out for.</p>

<ul class="wp-block-list">
 <li><strong>Always make sure you have the correct variant/group selected.</strong></li>
</ul>

<p class="wp-block-paragraph" style="margin-left: 40px;">The solution explorer often does not allow you to undo changes made. So if you make changes on the wrong variant/group, you might have to reset your local branch and try again. Watch out!</p>

<ul class="wp-block-list">
 <li><strong>If you want a setting to be variant dependent, don&rsquo;t forget to enable it in the solution explorer item&rsquo;s properties.</strong></li>
</ul>

<p class="wp-block-paragraph" style="margin-left: 40px;">Otherwise switching variants will have no effect!</p>

<ul class="wp-block-list">
 <li><strong>Variants are best used sparingly.</strong></li>
</ul>

<p class="wp-block-paragraph" style="margin-left: 40px;">There&rsquo;s no need to make everything variant dependent; this will just introduce another failure point for you and your team. Imagine not knowing a setting is variant dependent and making a change while you have a certain variant selected, only to discover months later that this update did not propagate to other relevant variants!&nbsp;For this reason, it may be prudent to make most solution explorer changes with the <strong>[All]</strong> group selected, unless you are specifically intending to make a change to a specific variant/group.</p>

<p class="wp-block-paragraph" style="margin-left: 40px;">If you&rsquo;re going to enable a setting to be variant dependent or going to use conditional pragmas in your code, have a good reason to do so. To avoid confusion, you should default to disabling variant dependency for any setting unless you have a reason to do otherwise.</p>

<p class="wp-block-paragraph" style="margin-left: 40px;">Be intentional and communicate variant dependency out to the rest of your team. And of course, documentation and commenting code are always good practices.</p>

<p class="wp-block-paragraph">&nbsp;</p>

<h2 class="wp-block-heading"><u><a id="Further Reference" name="Further Reference"></a>Further Reference</u></h2>

<p class="wp-block-paragraph"><em><a href="#Table of Contents">Back to Table of Contents</a></em></p>

<p class="wp-block-paragraph">For more information on variants, I would encourage reading Beckhoff&rsquo;s Infosys. Here are some good links:</p>

<ul class="wp-block-list">
 <li><a href="https://infosys.beckhoff.com/english.php?content=../content/1033/variant_management/index.html&amp;id=640168702518993771" target="_blank">Variant Management</a></li>
 <li><a href="https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_plc_intro/2526889867.html&amp;id=4368271537662055795" target="_blank">General Use of Pragmas</a></li>
 <li><a href="https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_plc_intro/2529795979.html&amp;id=" target="_blank">Conditional Pragmas</a></li>
 <li><a href="https://infosys.beckhoff.com/english.php?content=../content/1033/tf50x0_tc3_nc_ptp/2834717323.html&amp;id=8250271195349757571" target="_blank">Simulating Axes</a></li>
</ul>

<p class="wp-block-paragraph">There is definitely more potential for project variants than discussed here. Leave a comment below if you have used TwinCAT variants/have interesting examples of novel applications for them! If you&rsquo;ve run into &ldquo;gotchas&rdquo; that arose from the use of variants, let us know here as well, so we can all learn and avoid potential problems in the future.</p>

<p class="wp-block-paragraph"><em>Thanks to <a href="https://static.dmcinfo.com/about/employee-bios/kevin-staniszewski">Kevin Staniszewski</a> for contributing additional content to this article.</em></p>

<p class="wp-block-paragraph"><a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/plc-programming/beckhoff-and-twincat-3-programming"><strong>Learn more about DMC&apos;s Beckhoff and TwinCAT 3 programming expertise.</strong></a><br />
&nbsp;</p>
<p>The post <a href="https://static.dmcinfo.com/blog/18781/twincat-project-variants/">TwinCAT Project Variants</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Executing Command-Line Commands in TwinCAT</title>
		<link>https://static.dmcinfo.com/blog/19413/executing-command-line-commands-in-twincat/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Mon, 22 Mar 2021 15:33:02 +0000</pubDate>
				<category><![CDATA[Beckhoff PLC]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[PLC]]></category>
		<category><![CDATA[Beckhoff]]></category>
		<category><![CDATA[TwinCAT]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/19413/executing-command-line-commands-in-twincat/</guid>

					<description><![CDATA[<p>From reading and writing XML files to restarting the IPC, TwinCAT PLCs offer a lot of functionality through their&#160;built-in libraries. Additionally, TwinCAT runs on a Windows environment that can offer an even wider variety of functionalities to the user. In this blog, I will be discussing how to leverage TwinCAT&#8217;s ability to send commands to [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/19413/executing-command-line-commands-in-twincat/">Executing Command-Line Commands in TwinCAT</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">From reading and writing XML files to restarting the IPC, TwinCAT PLCs offer a lot of functionality through their&nbsp;built-in libraries. Additionally, TwinCAT runs on a Windows environment that can offer an even wider variety of functionalities to the user. In this blog, I will be discussing how to leverage TwinCAT&rsquo;s ability to send commands to the Windows command-line interface in order to expand its capabilities.&nbsp;</p>

<p class="wp-block-paragraph">To send such commands through a TwinCAT PLC, we can use the function NT_StartProcess in the TwinCAT Utilities Library. This function simply starts a process on the Windows computer and allows you to pass in command-line parameters along with it. Therefore, with the correct syntax, we can pass in commands to the Windows command line.</p>

<h2 class="wp-block-heading">Process</h2>

<p class="wp-block-paragraph">To start, we must make sure we import the Utilities Library. This can be done by right-clicking the references tab in the project tree and clicking &quot;Add Library.&quot; Select the Utilities Library and press &quot;OK.&quot;</p>

<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Utilities-Library.png"  /></figure>

<p class="wp-block-paragraph">To utilize the NT_StartProcess function, you first need to locate the path to the executable. The best way to find the path is to open the command prompt and enter:</p>

<pre class="”brush:xml”">
 
where cmd
</pre>

<p class="wp-block-paragraph">&nbsp;<figure class="wp-block-image"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Command-Prompt.png"  /></figure></p>

<p class="wp-block-paragraph"><em>Note: The path will likely be at C:\Windows\System32\cmd.exe</em></p>

<p class="wp-block-paragraph">Once you&rsquo;ve located the path to the executable, you need to pass in the path to the command-line executable on the system as PATHSTR, and a string for the command you wish to execute as COMDLINE. In order to properly format the command string, all you have to do is prepend &lsquo;/C &lsquo; to whatever command you wish to execute, making sure to include the space.&nbsp;</p>

<h2 class="wp-block-heading">Moving&nbsp;Files</h2>

<p class="wp-block-paragraph">For this example, I&rsquo;ll demonstrate how we can move a file on the Windows file system. This is something that is able to be done entirely within TwinCAT, but&nbsp;is much easier and quicker to do through the command-line interface. Here we are using the CONCAT function to build out our command.</p>

<pre class="”brush:xml”">

// Build Command String
sCommand := &apos;/C &apos;; 				// Special command indicating command string input
sCommand := CONCAT(sCommand, &apos;move &apos;);		// Add move command
sCommand := CONCAT(sCommand, sTargetFilePath);	// Add target file
sCommand := CONCAT(sCommand, &apos; &apos;);			// Required space for command 
sCommand := CONCAT(sCommand, sTargetDirectory);	// Add target location

</pre>

<p class="wp-block-paragraph">Passing both strings into NT_StartProcess and triggering the START bit will cause that command to be executed.</p>

<pre class="”brush:xml”">

Process(
	NETID := &apos;&apos;, 						// Local System
	PATHSTR := &apos;C:\Windows\System32\cmd.exe&apos;, 		// Path to local cmd executable
	COMNDLINE := sCommand,				// Command to be executed
	ERR =&gt; bError,						// Error Output
	ERRID =&gt; iErrorId					// Error Id Output
);

</pre>

<p class="wp-block-paragraph">You will likely not see the command prompt appear, but it may for more lengthy processes.&nbsp;</p>

<p class="wp-block-paragraph">Keep in mind that it can be difficult to debug these command executions.&nbsp;If the path to the executable or the syntax of the command is incorrect,&nbsp;you will never see any command window pop up&nbsp;and likely will not receive an error. I suggest confirming the command works in an instance of the command prompt before porting it over to TwinCAT. More information on the other functionalities of the NT_StartProcess function can be found on <a href="https://infosys.beckhoff.com/english.php?content=../content/1033/tcplclib_tc2_utilities/35042443.html&amp;id=" target="_blank">Beckhoff&rsquo;s website</a>.</p>

<h2 class="wp-block-heading">Working Example</h2>

<p class="wp-block-paragraph"><strong>Variable Declaration</strong></p>

<pre class="”brush:xml”">

PROGRAM MAIN
VAR
	Process			: NT_StartProcess;
	sTargetFilePath  	: STRING(255);
	sTargetDirectory 	: STRING(255);
	sCommand		: STRING(255);
	bTrigger		: BOOL := FALSE;
	bError			: BOOL;
	iErrorId			: UDINT;
END_VAR

</pre>

<p class="wp-block-paragraph"><strong>Logic</strong></p>

<pre class="”brush:xml”">

// File Locations
sTargetFilePath := &apos;C:\NET-DRIVE\NewOrders\Original.xml&apos;;
sTargetDirectory := &apos;C:\NET-DRIVE\OldOrders&apos;;

// Build Command String
sCommand := &apos;/C &apos;; 					// Special command indicating command string input
sCommand := CONCAT(sCommand, &apos;move &apos;);		// Add move command
sCommand := CONCAT(sCommand, sTargetFilePath);	// Add target file
sCommand := CONCAT(sCommand, &apos; &apos;);			// Required space for command 
sCommand := CONCAT(sCommand, sTargetDirectory);	// Add target location

// Output -&gt; &lsquo;/C move C:\NET-DRIVE\NewOrders\Original.xml &apos;C:\NET-DRIVE\OldOrders&rsquo;



Process(
	NETID := &apos;&apos;, 					// Local System
	PATHSTR := &apos;C:\Windows\System32\cmd.exe&apos;, 	// Path to local cmd executable
	COMNDLINE := sCommand,			// Comnmand to be executed
	ERR =&gt; bError,					// Error Output
	ERRID =&gt; iErrorId				// Error Id Output
);

// Trigger Command
IF bTrigger THEN
	bTrigger := FALSE;
	Process(START:=TRUE);
	Process(START:=FALSE);
END_IF

</pre>

<p class="wp-block-paragraph">TwinCAT natively offers a large amount of functionality to the user. The NT_StartProcess function&nbsp;is a great way to expand its&nbsp;capabilities&nbsp;to start programs and custom scripts from the PLC. Now, through the process described in this article, we can use the TwinCAT PLC to access the windows command prompt!</p>

<p class="wp-block-paragraph"><strong>Read more about DMC&rsquo;s </strong><a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/plc-programming/beckhoff-and-twincat-3-programming"><strong>Beckhoff and TwinCAT programming expertise</strong></a><strong> and </strong><a href="/contact"><strong>contact us</strong></a><strong> to get started on your next project. </strong></p>
<p>The post <a href="https://static.dmcinfo.com/blog/19413/executing-command-line-commands-in-twincat/">Executing Command-Line Commands in TwinCAT</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
