Warning

You are reading an old version of this documentation. If you want up-to-date information, please have a look at 4.2 .

Example - Beckhoff TwinCAT

This section gives an example of a simple integration of EYE+ with the EtherCAT module in Beckhoff TwinCAT version 3.1.

Prerequisites

Before you start, please make sure you have downloaded the following files:
  • EYE+ EtherCAT ESI file (electronic datasheet)

  • Optionally, EYE+ TwinCAT Project template, containing predeclared variables for easier integration

These files can be downloaded from EtherCAT Downloads.

Once you have downloaded the necessary files, please make sure to install the ESI file in the Beckhoff TwinCAT’s installation folder:

<path_to_twincat_install>\3.1\Config\Io\EtherCAT

Where <path_to_twincat_install> is usually C:\TwinCAT\ .

After installing the ESI file in the correct folder, please make sure you have restarted Beckhoff TwinCAT.

Basic integration

Once everything is in place, you can proceed with creating a new Beckhoff TwinCAT project. Then, make sure you are in Configuration Mode by pressing the following icon in the top left part:

../../../_images/twincat_config_mode.png

After that, you are ready to scan the EtherCAT bus to recognize and locate your EYE+ and the master device. The scan option is available by right-clicking on Devices, located in the left pane:

../../../_images/twincat_scan.png

The scanning process might take a few seconds, it will find all the devices currently connected to the bus.

Note

If you do not see your EYE+ in the list after the scan has finished, please make sure it is correctly connected and powered-on. If the problem persists, please contact our support team.

After the scan is completed, you should see your EYE+ box in the list under Devices:

../../../_images/twincat_scan_complete.png

If you have downloaded the optional template, please follow the next steps. Importing the template creates all the necessary variables to fully take advantage of your EYE+. Importing the template is straightforward, right click on your PLC project an click on Import From ZIP:

../../../_images/twincat_import_template.png

If successful, you should have entire structures of variables available:

../../../_images/twincat_variables.png

You will need to build the project so that the variables are available from within TwinCAT. Mapping the variables to EYE+’s own variables can be achieved easily with the Multi Link functionality:

../../../_images/twincat_variables_built.png
../../../_images/twincat_multilink.png

Once the variables have been mapped, and after restarting in running mode, you should be able to get live feedback of the registers:

../../../_images/twincat_prod.png

The following sample code allows you to start a production and get your first parts for a recipe that was previously created on your EYE+ controller. To do that, set udRecipeID to the ID of that recipe, then set boStart to True. The coordinates of the part found are returned in reRobotTargetX, reRobotTargetY and reRobotTargetRz.

(*
 * This sample code is distributed under the license CC0 1.0 Universal,
 * you can get a copy of the license at https://creativecommons.org/publicdomain/zero/1.0/
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *)

 VAR
         udRecipeID: UDINT;
         boStart: BOOL;
         R_TRIG_Start: R_TRIG;
         boStop: BOOL;
         R_TRIG_Stop: R_TRIG;
         boClearError : BOOL;
         inLastErrorID: UDINT;
         eState: UDINT;
         reRobotTargetX: REAL;
         reRobotTargetY: REAL;
         reRobotTargetRz: REAL;
 END_VAR

 VAR CONSTANT
         STATE_IDLE: UDINT := 0;
         STATE_START_PRODUCTION: UDINT := 10;
         STATE_ROBOT_MOVE_OUT_FOV: UDINT := 20;
         STATE_GET_PART: UDINT := 30;
         STATE_ROBOT_PICK_PLACE: UDINT := 50;
         STATE_STOP_PRODUCTION: UDINT := 60;
         STATE_ERROR: UDINT := 100;
 END_VAR

 R_TRIG_Start(CLK:= boStart);
 R_TRIG_Stop(CLK:= boStop);

 CASE eState OF

         STATE_IDLE:
                 IF R_TRIG_Start.Q THEN
                         eState := STATE_START_PRODUCTION;
                 END_IF

         STATE_START_PRODUCTION:
                 EYEplus.suEYEplusOutputGLO.udRecipeIDGOU := udRecipeID;
                 EYEplus.suEYEplusOutputGLO.boStartProductionTriggerGOU := TRUE;

                 IF EYEplus.suEYEplusInputGLO.boStartProductionDoneGIN AND NOT EYEplus.suEYEplusInputGLO.boIsErrorGIN THEN
                         EYEplus.suEYEplusOutputGLO.boStartProductionTriggerGOU := FALSE;
                         eState := STATE_ROBOT_MOVE_OUT_FOV;
                 ELSIF EYEplus.suEYEplusInputGLO.boIsErrorGIN THEN
                         EYEplus.suEYEplusOutputGLO.boStartProductionTriggerGOU := FALSE;
                         eState := STATE_ERROR;
                 END_IF

         STATE_ROBOT_MOVE_OUT_FOV:
                 //Robot move out of field of view
                 //Check that the movement is done before to go first get_part
                 eState := STATE_GET_PART;

         STATE_GET_PART:
                 EYEplus.suEYEplusOutputGLO.boGetPartTriggerGOU := TRUE;

                 IF EYEplus.suEYEplusInputGLO.boGetPartDoneGIN AND NOT EYEplus.suEYEplusInputGLO.boIsErrorGIN THEN
                         reRobotTargetX  := EYEplus.suEYEplusInputGLO.rePose1XGIN;
                         reRobotTargetY  := EYEplus.suEYEplusInputGLO.rePose1YGIN;
                         reRobotTargetRz := EYEplus.suEYEplusInputGLO.rePose1RzGIN;
                         EYEplus.suEYEplusOutputGLO.boGetPartTriggerGOU := FALSE;
                         eState := STATE_ROBOT_PICK_PLACE;
                 ELSIF EYEplus.suEYEplusInputGLO.boIsErrorGIN THEN
                         EYEplus.suEYEplusOutputGLO.boGetPartTriggerGOU := FALSE;
                         eState := STATE_ERROR;
                 END_IF

         STATE_ROBOT_PICK_PLACE:
                 //Robot pick and place the part
                 //Check that the movement is done before to go make another get_part
                 eState := STATE_GET_PART;

         STATE_STOP_PRODUCTION:
                 EYEplus.suEYEplusOutputGLO.udStopStateGOU := 16#FF;

                 IF EYEplus.suEYEplusInputGLO.boStopStateDoneGIN AND NOT EYEplus.suEYEplusInputGLO.boIsErrorGIN THEN
                         EYEplus.suEYEplusOutputGLO.udStopStateGOU := 16#00;
                         eState := STATE_IDLE;
                 ELSIF EYEplus.suEYEplusInputGLO.boIsErrorGIN THEN
                         EYEplus.suEYEplusOutputGLO.udStopStateGOU := 16#00;
                         eState := STATE_ERROR;
                 END_IF

         STATE_ERROR:
                 EYEplus.suEYEplusOutputGLO.udStopStateGOU := 16#00;
                 EYEplus.suEYEplusOutputGLO.boStartProductionTriggerGOU := FALSE;
                 EYEplus.suEYEplusOutputGLO.boGetPartTriggerGOU := FALSE;

                 inLastErrorID := EYEplus.suEYEplusInputGLO.udErrorIDGIN;
                 EYEplus.suEYEplusOutputGLO.boClearErrorTriggerGOU := boClearError;

                 IF NOT EYEplus.suEYEplusInputGLO.boIsErrorGIN THEN
                         EYEplus.suEYEplusOutputGLO.boClearErrorTriggerGOU := FALSE;
                         eState := STATE_STOP_PRODUCTION;
                 END_IF;
 END_CASE

 IF R_TRIG_Stop.Q THEN
         EYEplus.suEYEplusOutputGLO.boStartProductionTriggerGOU := FALSE;
         EYEplus.suEYEplusOutputGLO.boGetPartTriggerGOU := FALSE;
         EYEplus.suEYEplusOutputGLO.boClearErrorTriggerGOU := FALSE;

         eState := STATE_STOP_PRODUCTION;
 END_IF