[Home]Etherlab

LinuxCNCKnowledgeBase | RecentChanges | PageIndex | Preferences | LinuxCNC.org

Using Beckhoff EtherCAT(TM) I/O Bus clamps with EMC

A german control systems firm called [Beckhoff Automation] sells a bus terminal system called EtherCAT. It is build of a Bus couppler and a number of input or output modules as terminals. You can order digital drive controllers speaking EtherCAT, too. Every module directly talks ethernet frames and optionally UDP. The modules insert and extract their data to/from the frame while transmitting it.

If you have a computer with a supported ethernet card, you can use this terminals and drive controllers with emc.

I will describe how to get this to work using the open source [etherlab library] here. A list of supported ethernet chipsets can be found at http://www.etherlab.org/en/ethercat/hardware.php


Hardware Setup

You can get an evaluation package including a bus coupler Type EK110, two 4 channel input modules EL1014 and two 4 channel output modules EL2004.

Here is a photo of such a setup:

From left to right:

  1. 24V power supply
  2. EK1100 bus coupler with power input clamp
  3. EL2004 4 chganel digital output
  4. EL2004
  5. EL1014 4 chanel digital input
  6. EL1014
  7. Bus end clamp
  8. Relais for testing the output module
  9. Button for testing the input module

I just wired the power supply and the button to one of the input terminals and the relais to one of the output terminals. The green cable is connected directly to the rtl8139 ethernet card in my pc.

They also offer modules for analog input, analog output, encoder input and even a 4-axis machine control module (combines encoders, DA and I/O). And you can plug in digital drive modules wich manage one to three motors including tachos and encoders/linear scales. Just look at their web site.

Software needed

This is the software I installed.

I did that manually, because of the patches. If you choose to use the live cd you will at least need to install patched network drivers and etherlab.

Software Configuration

kernel

Start from kernel 2.6.32.19, use the latest stable 2.6.32 availiable. Apply the rtai adeos patch from the rtai directory Configure your kernel. Be sure to check "processor type and features -> interrupt pipeline"

rtai

configure rtai. you can use menuconfig or configure to do this. Don't forget to check "base system -> other features -> mathfuns support in kernel" You need to tell rtai where your kernel sources are located if not at the default space.

etherlab master

etherlab master comes with its own patched versions of the default linux network drivers. I had to patch my linux driver for the current version of rtl8139. I sent that patch upstream so maybe it is included by now.

configure etherlab master using the configure script as described in the readme. Hint: use --prefix=/your/prefix/here --with-linux-dir=/your/linux/dir/here

After installing you have to edit /etc/ethercat to select the master device MAC and the kernel driver module to load. To test-start the etherlab master and do basic communication you will need following commands:

/etc/init.d/realtime start
/etc/init.d/ethercat start

Immediately after you insert ethe etercat module, you will see blinking network led on the bus coupler. This is a preliminary mode. You can now query the bus topology and terminals and their design versions (very important for later use). To show the topology, issue:

ethercat slaves -v

The output looks like this:

<=== Master 0, Slave 0 ===
State: PREOP
Flag: +
Identity:
  Vendor Id:       0x00000002
  Product code:    0x044c2c52
  Revision number: 0x00110000
  Serial number:   0x00000000
DL information:
  FMMU bit operation: no
  Distributed clocks: yes, 64 bit
  DC system time transmission delay: 0 ns
Port  Type  Link  Loop    Signal  NextSlave  RxTime [ns]  Diff [ns]   NextDc [ns]
   0  MII   up    open    yes             -   1634392210           0           0
   1  EBUS  up    open    yes             1   1634393360        1150         140
   2  MII   down  closed  no              -            -           -           -
   3  N/A   down  closed  no              -            -           -           -
General:
  Group: SystemBk
  Image name: 
  Order number: EK1100
  Device name: EK1100 EtherCAT-Koppler (2A E-Bus)
  Flags:
    Enable SafeOp: no
    Enable notLRW: no
  Current consumption: -2000 mA
=== Master 0, Slave 1 ===
State: PREOP
Flag: +
Identity:
  Vendor Id:       0x00000002
  Product code:    0x07d43052
  Revision number: 0x00100000
  Serial number:   0x00000000
DL information:
  FMMU bit operation: no
  Distributed clocks: yes, 64 bit
  DC system time transmission delay: 140 ns
Port  Type  Link  Loop    Signal  NextSlave  RxTime [ns]  Diff [ns]   NextDc [ns]
   0  EBUS  up    open    yes             0   1634107860           0         140
   1  EBUS  up    open    yes             2   1634108730         870         140
   2  N/A   down  closed  no              -            -           -           -
   3  N/C   down  closed  no              -            -           -           -
General:
  Group: DigOut
  Image name: 
  Order number: EL2004
  Device name: EL2004 4K. Dig. Ausgang 24V, 0.5A
  Flags:
    Enable SafeOp: no
    Enable notLRW: no
  Current consumption: 100 mA
=== Master 0, Slave 2 ===
State: PREOP
Flag: +
Identity:
  Vendor Id:       0x00000002
  Product code:    0x07d43052
  Revision number: 0x00100000
  Serial number:   0x00000000
DL information:
  FMMU bit operation: no
  Distributed clocks: yes, 64 bit
  DC system time transmission delay: 280 ns
Port  Type  Link  Loop    Signal  NextSlave  RxTime [ns]  Diff [ns]   NextDc [ns]
   0  EBUS  up    open    yes             1   1635119480           0         140
   1  EBUS  up    open    yes             3   1635120070         590         145
   2  N/A   down  closed  no              -            -           -           -
   3  N/C   down  closed  no              -            -           -           -
General:
  Group: DigOut
  Image name: 
  Order number: EL2004
  Device name: EL2004 4K. Dig. Ausgang 24V, 0.5A
  Flags:
    Enable SafeOp: no
    Enable notLRW: no
  Current consumption: 100 mA
=== Master 0, Slave 3 ===
State: PREOP
Flag: +
Identity:
  Vendor Id:       0x00000002
  Product code:    0x03f63052
  Revision number: 0x00100000
  Serial number:   0x00000000
DL information:
  FMMU bit operation: no
  Distributed clocks: yes, 64 bit
  DC system time transmission delay: 425 ns
Port  Type  Link  Loop    Signal  NextSlave  RxTime [ns]  Diff [ns]   NextDc [ns]
   0  EBUS  up    open    yes             2   1634492040           0         145
   1  EBUS  up    open    yes             4   1634492340         300         150
   2  N/A   down  closed  no              -            -           -           -
   3  N/C   down  closed  no              -            -           -           -
General:
  Group: DigIn
  Image name: TERM_DI
  Order number: EL1014
  Device name: EL1014 4K. Dig. Eingang 24V, 10�s
  Flags:
    Enable SafeOp: no
    Enable notLRW: no
  Current consumption: 90 mA
=== Master 0, Slave 4 ===
State: PREOP
Flag: +
Identity:
  Vendor Id:       0x00000002
  Product code:    0x03f63052
  Revision number: 0x00100000
  Serial number:   0x00000000
DL information:
  FMMU bit operation: no
  Distributed clocks: yes, 64 bit
  DC system time transmission delay: 575 ns
Port  Type  Link  Loop    Signal  NextSlave  RxTime [ns]  Diff [ns]   NextDc [ns]
   0  EBUS  up    open    yes             3   1634388330           0         150
   1  EBUS  down  closed  no              -            -           -           -
   2  N/A   down  closed  no              -            -           -           -
   3  N/C   down  closed  no              -            -           -           -
General:
  Group: DigIn
  Image name: TERM_DI
  Order number: EL1014
  Device name: EL1014 4K. Dig. Eingang 24V, 10�s
  Flags:
    Enable SafeOp: no
    Enable notLRW: no
  Current consumption: 90 mA

The interesting thing is the bus topology and the Revision of each Slave. The latter caught me becaus I programmed for an older revision of the modules first and wondered why my module would not load until I figured out that the new revision supports single bit addressing instead of returning byte data.

Glue Module

The glue module is adapted, the original code is from Florian Pose, Ingenieurgemeinschaft IgH?. To compile the glue module you have to change directory to your emc source dir. There, you can do the compile by issuing:

sudo bin/comp --install ../your/path/here/ethercat.comp

Here is the comp module to make this setup working.


component ethercat"Ethercat.";

pin out bit eingang_0; 
pin out bit eingang_1;
pin out bit eingang_2;
pin out bit eingang_3;

pin out bit eingang_4;
pin out bit eingang_5;
pin out bit eingang_6;
pin out bit eingang_7;

pin in bit ausgang_0; 
pin in bit ausgang_1;
pin in bit ausgang_2;
pin in bit ausgang_3;

pin in bit ausgang_4;
pin in bit ausgang_5;
pin in bit ausgang_6;
pin in bit ausgang_7;

option extra_setup;
option extra_cleanup;

//option constructable no;

function update nofp;
license "GPL";

;;

#include "/opt/ethercat/include/ecrt.h"

/*****************************************************************************/

// EtherCAT
static ec_master_t *master = NULL;
static ec_domain_t *domain1 = NULL;
spinlock_t master_lock = SPIN_LOCK_UNLOCKED;
static ec_master_state_t master_status, old_status = {};

// data fields
static uint8_t *domain1_pd; // process data memory
// offsets to data fields
static unsigned int o_dig_in[8],  bo_dig_in[8];
static unsigned int o_dig_out[8], bo_dig_out[8];

// pdo definitions may be read from autogenerated file
//#include "ethercat_cstruct.c"

#define Beckhoff_EL2004 0x00000002, 0x07D43052
#define Beckhoff_EL1014 0x00000002, 0x03F63052

const static ec_pdo_entry_reg_t domain1_pdo_regs[] = {
        { 0, 1,      Beckhoff_EL2004, 0x7000, 1, &o_dig_out[0], &bo_dig_in[0]},
        { 0, 1,      Beckhoff_EL2004, 0x7010, 1, &o_dig_out[1], &bo_dig_in[1]},
        { 0, 1,      Beckhoff_EL2004, 0x7020, 1, &o_dig_out[2], &bo_dig_in[2]},
        { 0, 1,      Beckhoff_EL2004, 0x7030, 1, &o_dig_out[3], &bo_dig_in[3]},

        { 0, 2,      Beckhoff_EL2004, 0x7000, 1, &o_dig_out[4], &bo_dig_in[4]},
        { 0, 2,      Beckhoff_EL2004, 0x7010, 1, &o_dig_out[5], &bo_dig_in[5]},
        { 0, 2,      Beckhoff_EL2004, 0x7020, 1, &o_dig_out[6], &bo_dig_in[6]},
        { 0, 2,      Beckhoff_EL2004, 0x7030, 1, &o_dig_out[7], &bo_dig_in[7]},

	{ 0, 3,      Beckhoff_EL1014, 0x6000, 1, &o_dig_in[0] , &bo_dig_out[0]},
	{ 0, 3,      Beckhoff_EL1014, 0x6010, 1, &o_dig_in[1] , &bo_dig_out[1]},
	{ 0, 3,      Beckhoff_EL1014, 0x6020, 1, &o_dig_in[2] , &bo_dig_out[2]},
	{ 0, 3,      Beckhoff_EL1014, 0x6030, 1, &o_dig_in[3] , &bo_dig_out[3]},

	{ 0, 4,      Beckhoff_EL1014, 0x6000, 1, &o_dig_in[4] , &bo_dig_out[4]},
	{ 0, 4,      Beckhoff_EL1014, 0x6010, 1, &o_dig_in[5] , &bo_dig_out[5]},
	{ 0, 4,      Beckhoff_EL1014, 0x6020, 1, &o_dig_in[6] , &bo_dig_out[6]},
	{ 0, 4,      Beckhoff_EL1014, 0x6030, 1, &o_dig_in[7] , &bo_dig_out[7]},

        /* { 0, 1,      Beckhoff_EL2004, 0x7000, 1, &o_dig_out[0], NULL}, */
	/* { 0, 4,      Beckhoff_EL1014, 0x6000, 1, &o_dig_in[0] , NULL}, */
    {}
};

/***********************************************************************
*                  LOCAL FUNCTION DECLARATIONS                         *
************************************************************************/

void request_lock(void *data)
{
    spin_lock(&master_lock);
}

void release_lock(void *data)
{
    spin_unlock(&master_lock);
}


/*****************************************************************************/
EXTRA_SETUP() {

    rtapi_print_msg(RTAPI_MSG_INFO,"Starting...\n");
    //printk(KERN_INFO PFX "Starting...\n");

    if (!(master = ecrt_request_master(0))) {
	rtapi_print_msg(RTAPI_MSG_INFO,"BRequesting master 0 failed!\n");
        //printk(KERN_ERR PFX "Requesting master 0 failed!\n");
        goto out_return;
    }

    ecrt_master_callbacks(master, request_lock, release_lock, NULL);

	rtapi_print_msg(RTAPI_MSG_INFO,"Registering domain...\n");
    //printk(KERN_INFO PFX "Registering domain...\n");
    if (!(domain1 = ecrt_master_create_domain(master))) {
	rtapi_print_msg(RTAPI_MSG_INFO,"Domain creation failed!\n");
        //printk(KERN_ERR PFX "Domain creation failed!\n");
        goto out_release_master;
    }

	rtapi_print_msg(RTAPI_MSG_INFO,"Registering PDOs...\n");
    //rintk(KERN_INFO PFX "Registering PDOs...\n");

	if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_pdo_regs)) {
	rtapi_print_msg(RTAPI_MSG_INFO,"PDO registration failed!\n");
        //printk(KERN_ERR PFX "PDO registration failed!\n");
        goto out_release_master;
    }

	rtapi_print_msg(RTAPI_MSG_INFO,"Activating master...\n");
    //printk(KERN_INFO PFX "Activating master...\n");
    if (ecrt_master_activate(master)) {
	rtapi_print_msg(RTAPI_MSG_INFO,"Failed to activate master!\n");
        //printk(KERN_ERR PFX "Failed to activate master!\n");
        goto out_release_master;
    }


    domain1_pd = ecrt_domain_data(domain1);
	
    rtapi_print_msg(RTAPI_MSG_INFO,"Started.\n");
    //printk(KERN_INFO PFX "Started.\n");
    return 0;

 out_release_master:
	rtapi_print_msg(RTAPI_MSG_INFO,"Releasing master...\n");
    //printk(KERN_ERR PFX "Releasing master...\n");
    ecrt_release_master(master);
    master= NULL;
 out_return:
	rtapi_print_msg(RTAPI_MSG_INFO,"Failed to load. Aborting.\n");
    //printk(KERN_ERR PFX "Failed to load. Aborting.\n");
    return -1;
}

EXTRA_CLEANUP() {
	
	rtapi_print_msg(RTAPI_MSG_INFO,"Stopping...\n");
	//printk(KERN_INFO PFX "Stopping...\n");

	if (master) {
		rtapi_print_msg(RTAPI_MSG_INFO,"Releasing master...\n");
		//printk(KERN_INFO PFX "Releasing master...\n");
		ecrt_release_master(master);
	}

	rtapi_print_msg(RTAPI_MSG_INFO,"Unloading.\n");
	//printk(KERN_INFO PFX "Unloading.\n");
}

/*****************************************************/

/*****************************************************/
FUNCTION(update) { 


    	// receive
    	spin_lock(&master_lock);
    	ecrt_master_receive(master);
    	ecrt_domain_process(domain1);
    	spin_unlock(&master_lock);

	eingang_0 = EC_READ_BIT( domain1_pd+o_dig_in[0], bo_dig_in[0]);
	eingang_1 = EC_READ_BIT( domain1_pd+o_dig_in[1], bo_dig_in[1]);
	eingang_2 = EC_READ_BIT( domain1_pd+o_dig_in[2], bo_dig_in[2]);
	eingang_3 = EC_READ_BIT( domain1_pd+o_dig_in[3], bo_dig_in[3]);
	
	eingang_4 = EC_READ_BIT( domain1_pd+o_dig_in[4], bo_dig_in[4]);
	eingang_5 = EC_READ_BIT( domain1_pd+o_dig_in[5], bo_dig_in[5]);
	eingang_6 = EC_READ_BIT( domain1_pd+o_dig_in[6], bo_dig_in[6]);
	eingang_7 = EC_READ_BIT( domain1_pd+o_dig_in[7], bo_dig_in[7]);

	EC_WRITE_BIT(domain1_pd+o_dig_out[0], bo_dig_out[0], ausgang_0);
	EC_WRITE_BIT(domain1_pd+o_dig_out[1], bo_dig_out[1], ausgang_1);
	EC_WRITE_BIT(domain1_pd+o_dig_out[2], bo_dig_out[2], ausgang_2);
	EC_WRITE_BIT(domain1_pd+o_dig_out[3], bo_dig_out[3], ausgang_3);

	EC_WRITE_BIT(domain1_pd+o_dig_out[4], bo_dig_out[4], ausgang_4);
	EC_WRITE_BIT(domain1_pd+o_dig_out[5], bo_dig_out[5], ausgang_5);
	EC_WRITE_BIT(domain1_pd+o_dig_out[6], bo_dig_out[6], ausgang_6);
	EC_WRITE_BIT(domain1_pd+o_dig_out[7], bo_dig_out[7], ausgang_7);

	/* eingang_0= EC_READ_BIT( domain1_pd+o_dig_in[0],0); */
	/* EC_WRITE_BIT(domain1_pd+o_dig_out[0],0,ausgang_0); */

        spin_lock(&master_lock);
        ecrt_master_state(master, &master_status);
        spin_unlock(&master_lock);

        if (master_status.al_states != old_status.al_states) {
		rtapi_print_msg(RTAPI_MSG_INFO,"bus status changed to %i.\n", master_status.al_states);
        }
        if (master_status.slaves_responding !=
                old_status.slaves_responding) {
			rtapi_print_msg(RTAPI_MSG_INFO,"slaves_responding changed to %u.\n", master_status.slaves_responding);
        }

        old_status = master_status;


    	// send
    	spin_lock(&master_lock);
    	ecrt_domain_queue(domain1);
    	spin_unlock(&master_lock);

    	spin_lock(&master_lock);
    	ecrt_master_send(master);
    	spin_unlock(&master_lock);

}

Note: This is not the best design. I have to figure out how access bit data without wasting two 32bit intergers as data fields and offsets for every single bit.

If this system is getting adapted by emc, it would be good to provide an automated build script for creating this module from a given ethercat topology.

Configuring and testing realtime

I just toss in the commands I issued here and will document them later.

Getting hal up and running:

insmod /opt/realtime/modules/rtai_math.ko 
insmod /opt/realtime/modules/emc2/ethercat.ko 
halcmd  loadrt trivkins
halcmd  loadrt motmod servo_period_nsec=1000000 num_joints=3
halcmd addf ethercat.0.update servo-thread
halcmd start
This loads all modules, ties the ehtercat update task to the servo thread and starts the realtime thread. If you use it for production, you will certainly start emc and wire this inside a hal file.

For testing you can use this commands:

halcmd  show pin ethercat
halcmd setp ethercat.0.ausgang-0 true
halcmd setp ethercat.0.ausgang-0 false
This shows the status of the input ports and switches the output port 0 (my relais will click!)

You can check the configuration of your system while it is running by using ethercat config -v

The output will look like this:

Alias: 0
Position: 1
Vendor Id: 0x00000002
Product code: 0x07d43052
Attached slave: 1 (OP)
Watchdog divider: (Default)
Watchdog intervals: (Default)
SM0, Dir: Output, Watchdog: Default
  PDO 0x1600
    PDO entry 0x7000:01,  1 bit
  PDO 0x1601
    PDO entry 0x7010:01,  1 bit
  PDO 0x1602
    PDO entry 0x7020:01,  1 bit
  PDO 0x1603
    PDO entry 0x7030:01,  1 bit
SDO configuration:
  None.

Alias: 0
Position: 2
Vendor Id: 0x00000002
Product code: 0x07d43052
Attached slave: 2 (OP)
Watchdog divider: (Default)
Watchdog intervals: (Default)
SM0, Dir: Output, Watchdog: Default
  PDO 0x1600
    PDO entry 0x7000:01,  1 bit
  PDO 0x1601
    PDO entry 0x7010:01,  1 bit
  PDO 0x1602
    PDO entry 0x7020:01,  1 bit
  PDO 0x1603
    PDO entry 0x7030:01,  1 bit
SDO configuration:
  None.

Alias: 0
Position: 3
Vendor Id: 0x00000002
Product code: 0x03f63052
Attached slave: 3 (OP)
Watchdog divider: (Default)
Watchdog intervals: (Default)
SM0, Dir: Input, Watchdog: Default
  PDO 0x1a00
    PDO entry 0x6000:01,  1 bit
  PDO 0x1a01
    PDO entry 0x6010:01,  1 bit
  PDO 0x1a02
    PDO entry 0x6020:01,  1 bit
  PDO 0x1a03
    PDO entry 0x6030:01,  1 bit
SDO configuration:
  None.

Alias: 0
Position: 4
Vendor Id: 0x00000002
Product code: 0x03f63052
Attached slave: 4 (OP)
Watchdog divider: (Default)
Watchdog intervals: (Default)
SM0, Dir: Input, Watchdog: Default
  PDO 0x1a00
    PDO entry 0x6000:01,  1 bit
  PDO 0x1a01
    PDO entry 0x6010:01,  1 bit
  PDO 0x1a02
    PDO entry 0x6020:01,  1 bit
  PDO 0x1a03
    PDO entry 0x6030:01,  1 bit
SDO configuration:
  None.

EtherCat (EtherLab) Experience with Xubuntu 8.04


LinuxCNCKnowledgeBase | RecentChanges | PageIndex | Preferences | LinuxCNC.org
This page is read-only. Follow the BasicSteps to edit pages. | View other revisions
Last edited June 4, 2014 6:43 am by A.Bausano (diff)
Search:
Published under a Creative Commons License