The EtherCAT master¶
Getting started¶
Ethercat terminals are usually connected in a loop with the EtherCAT master, via an ethernet interface. So we create a master object, and connect to that interface an scan the loop. This takes time, so in a good asyncronous fashion we need to use await, which can only be done in an async function:
import asyncio
from ebpfcat.ebpfcat import FastEtherCat
async def main():
master = FastEtherCat("eth0")
await master.connect()
print('Number of terminals:', await master.count())
asyncio.run(main())
Next we create an object for each terminal that we want to use. As an example, take some Beckhoff output terminal:
from ebpfcat.terminals import EL4104
out = EL4104(master)
This terminal needs to be initialized. The initialization method takes two arguments, the relative position in the loop, starting with 0 for the terminal directly connected to the interface, counting downwards to negative values. The second argument is the absolute address this terminal should be assigned to:
await out.initialize(-1, 20) # assign address 20 to the first terminal
The terminals are usually controlled by devices, where one terminal may be
controlled by several devices, or one device controls several terminals. The
devices are represented by Device
objects. Upon
instantiation, they are connected to the terminals:
from ebpfcat.devices import AnalogOutput
ao = AnalogOutput(out.ch1_value) # use channel 1 of terminal "out"
Devices are grouped into SyncGroup
, which means that their
terminals are always read and written at the same time. A device can only
belong to one SyncGroup
, but a terminal may be part of
several devices or sync groups. The sync group is also responsible to
constantly transfer data to and from the terminals such that they do not time
out and go into a safe state:
from ebpfcat.ebpfcat import SyncGroup
sg = SyncGroup(master, [ao]) # this sync group only contains one terminal
sg.start() # start operating the terminals
The AnalogOutput
in the examples is a pretty boring device, it can only
output a value like so:
ao.value = 5 # set the value on the terminal
For reference, here is a complete code example:
"""A simple example of an EtherCat control
this is only an illustrative example to be read. It will not work unless
you happen to have an EtherCat setup where a Beckhoff EL4101 terminal is
the second terminal in the line.
"""
import asyncio
from ebpfcat.ebpfcat import FastEtherCat, SyncGroup
from ebpfcat.devices import AnalogOutput
from ebpfcat.terminals import EL4104
async def main():
master = FastEtherCat("eth0")
await master.connect()
print("Number of terminals:", await master.count())
out = EL4104(master)
await out.initialize(-2, 20)
ao = AnalogOutput(out.ch2_value) # use channel 1 of terminal "out"
sg = SyncGroup(master, [ao]) # this sync group only contains one terminal
task = sg.start() # start operating the terminals
for i in range(10):
# we would measure an increasing value on the terminal output
ao.value = i
await asyncio.sleep(0.1)
task.cancel() # stop the sync group
asyncio.run(main())
Writing a device¶
Equipment controlled via the EtherCAT terminals often requires that a dedicated
device is written for it. Devices inherit from ebpfcat.Device
. They
declare which kind of data they want to communicate to the terminals as a
ebpfcat.TerminalVar
like so:
from ebpfcat.ebpfcat import Device, TerminalVar
class Motor(Device):
speed = TerminalVar()
position = TerminalVar()
Before they can be used, their TerminalVar
s need to be
initialized:
motor = Motor()
motor.speed = outputTerminal.speed
motor.position = encoderTerminal.value
whenever new data is read from the loop, the update()
method of the device is called, in which one can evaluate the
TerminalVar
s, or set them:
def update(self):
"""a idiotic speed controller"""
self.speed = (self.position - self.target) * self.pConst
Three methods of control¶
The communication with the terminals can happen in three different ways:
asynchronous: the communication happens ad-hoc whenever needed. This is done during initialization and for reading and writing configuration data, like CoE.
slow: the data is sent, received and processed via Python. This is good enough to around 100 Hz operation.
fast: the data is sent, received and processed using XDP in the Linux Kernel. Only very limited operations can be done, but the loop cycle frequency exceeds 10 kHz.
Adding new terminals¶
The elements of an EtherCat loop were used to be called slaves, but nowadays are referred to as SubDevices. As in a typical installation most of them are simply terminals, we call them such.
Everything in a terminal is controlled by reading or writing parameters in the
CoE address space. These addresses are a pair of a 16 bit and an 8 bit number,
usually seperated by a colon, as in 6010:13
. Most terminals allow these
parameters to be set asynchronously. Some of the parameters may be read or
written synchronously, so with every communication cycle.
The meaning of all these parameters can usually be found in the documentation
of the terminal. Additionally, terminals often have a self-description, which
can be read with the command line tool ec-info
:
$ ec-info eth0 --terminal 1 --sdo
this reads the first terminal’s self description (--sdo
). Add a --value
to also get the current values of the parameters. This prints out all known
self descriptions of CoE parameters.
Once we know the meaning of parameters, they may be read or written
asynchronously using sdo_read()
and
sdo_write()
.
For synchronous data access, a class needs to be defined that defines the
parameters one want to use synchronously. The parameters available for
synchronous operations can be found with the --pdo
parameter of the
ec-info
command. The class should inherit from
EBPFTerminal
and define a set of tuples called
comptibility
. The tuples should be the pairs of Ethercat product and vendor
id for all terminals supported by this class. Those can be found out with the
--ids
parameter of the ec-info
command.
Within the class, the synchronous parameters are defined via
ProcessDesc
. This descriptor takes the two parts of the CoE
address as parameters, plus an optional size parameter. This is usually
determined automatically, but this sometimes fails, in which case it may either
be defined via a format string like in the struct
module, or it
is an integer which is then a reference to the position of the bit in the
parameter to define a boolean flag.
For terminals which have several equivalent channels, one can define a
structure by inheriting from Struct
. Within this
class one defines the first set of parameters the same way one would do it
without. Once the class is defined, it can be instantiated in the terminal
class with a single argument which defines the offset in the CoE address space
for this structure. As an example, if on a two-channel terminal the first
channel has an address of 0x6000:12
and the following two 0x6010:12
and
0x6020:12
, one would instantiate three structs with arguments 0
,
0x10
and 0x20
.
A complete example of a four channel terminal looks as follows:
class EL3164(EBPFTerminal):
compatibility = {(2, 0x0c5c3052)}
class Channel(Struct):
attrs = ProcessDesc(0x6000, 1, 'H') # this is 2 bytes ('H')
value = ProcessDesc(0x6000, 0x11)
factor = 10/32767 # add bonus information as desired
offset = 0
channel1 = Channel(0) # adress 0x6000
channel2 = Channel(0x10) # address 0x6010
channel3 = Channel(0x20)
channel4 = Channel(0x30)
Inspecting the bus via the command line¶
Using the command line tool ec-info
one can learn many details about the
terminals on an EtherCat bus. As its first parameter, it always takes the
interface the bus is connected to, in the following examples we always take
eth0
. The --terminal
(or -t
) parameter may be used with the
position of the terminal on the bus to be inspected, otherwise all terminals
will be inspected. All other parameters indicate which information should be
shown.
The --ids
(or -i
) parameter shows the identification numbers of the
terminal from its EEPROM. As an example:
$ sudo ec-info eth0 -i -t3
terminal no 3
2:1B813052 revision 100034 serial 0
This means that terminal number 3 has vendor ID 2 (that is Beckhoff Automation), with product code 0x1B813052 (an EL7041 terminal), revision 0x100034 and serial number 0. Note that most vendors will leave the serial number 0, though in principle this can be changed.
The --names
(or -n
) parameter shows some readable text found in the
EEPROM of the terminal. This may be anything, but often is helpful in
identifying the terminal:
$ sudo ec-info eth0 -n -t12
terminal no 12
EL7031
DriveAxisTerminals
Antriebs- und Achsklemmen (EL7xxx)
EL7031 1K. Schrittmotor-Endstufe (24V, 1.5A)
Synchron
DC
A little less user friendly, but sometimes more informative variant is the
--eeprom
(or -e
) parameter, showing the content of the sections of the
EEPROM once as text and once as a hexadecimal representation:
$ sudo ec-info eth0 -e -t12
terminal no 12
3: b'1P079532SBTN000jb1061KES7031 Q1 2P242213130026'
31503037393533325342544e3030306a62313036314b4553373033312020202020202020202020202020202020202020202020205131202020203250323432323133313330303236
10: b'\x06\x06EL7031\x12DriveAxisTerminals"Antriebs- und Achsklemmen (EL7xxx),EL7031 1K. Schrittmotor-Endstufe (24V, 1.5A)\x08Synchron\x02DC\xff'
0606454c37303331124472697665417869735465726d696e616c7322416e7472696562732d20756e6420416368736b6c656d6d656e2028454c37787878292c454c3730333120314b2e20536368726974746d6f746f722d456e64737475666520283234562c20312e3541290853796e6368726f6e024443ff
30: b"\x02\x00\x01\x04\x0c'\x01\x00\x00\x00\x00\x04x\x00\x03\x003\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
020001040c270100000000047800030033000000000000000000000000000000
40: b'\x01\x02\x03\xff'
010203ff
41: b'\x00\x10\x80\x00&\x00\x01\x01\x80\x10\x80\x00"\x00\x01\x02\x00\x11\x08\x00$\x00\x01\x03\x80\x11\x08\x00 \x00\x01\x04'
0010800026000101801080002200010200110800240001038011080020000104
60: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x01\x00\x06\x00\x00\x00\x00\x00'
000000000000000000000000000000000000050000000000000000000000000000000000000000030100060000000000
Using the --pdo
(or -p
) parameter one can inspect the current PDO configuration, this are the CoE parameters available for synchronous read and write:
$ sudo ec-info eth0 -p -t12
terminal no 12
7000:02 OUT 0 1
7000:03 OUT 0 2
7000:04 OUT 0 3
7000:11 OUT 2 H
7010:01 OUT 4 0
7010:02 OUT 4 1
7010:03 OUT 4 2
7010:21 OUT 6 H
6000:02 IN 0 1
6000:03 IN 0 2
6000:04 IN 0 3
...
The first columns shows the CoE address, the second shows OUT for data written
to the terminal, IN for those read from it. The third column indicates the byte
adress in the synchronous datagram, and the last column either the bit within
that byte, or an indicator of the ssize of the parameter. The meaning of the
parameters can be found in the terminal’s documentation, or possibly via the
--sdo
parameter.
The CoE adresses shown here following a pattern that at least Beckhoff Automation follows: the 7xxx:xx range are the output parameters, the 6xxx:xx range are the input parameters.
The --sdo
(or -s
) paramter shows the terminal’s self description of
parameters. This self description, however, varies in quality depending on the
vendor. Let’s go through some of the output:
$ sudo ec-info eth0 -s -t12
terminal no 12
1000:
0: Device type UNSIGNED32 (32 bit) flags 7
1008:
0: Device name VISIBLE_STRING (48 bit) flags 7
1009:
0: Hardware version VISIBLE_STRING (16 bit) flags 7
100A:
0: Software version VISIBLE_STRING (16 bit) flags 7
1011:
1: SubIndex 001 UNSIGNED32 (32 bit) flags 3F
1018:
1: Vendor ID UNSIGNED32 (32 bit) flags 7
2: Product code UNSIGNED32 (32 bit) flags 7
3: Revision UNSIGNED32 (32 bit) flags 7
4: Serial number UNSIGNED32 (32 bit) flags 7
...
The output usually starts with some identification of the device itself. Note
that the output is grouped by CoE groups, so in the example the adress of the
serial number (last line) would be 1018:4. Adding the --values
(or -v
)
parameter also shows the current values of the CoE parameter, for numbers both
in decimal and hexadecimal:
$ sudo ec-info eth0 -s -v -t12
terminal no 12
1000:
0: Device type UNSIGNED32 (32 bit) flags 7
5001 1389
1008:
0: Device name VISIBLE_STRING (48 bit) flags 7
ES7031
'ES7031'
1009:
0: Hardware version VISIBLE_STRING (16 bit) flags 7
13
'13'
100A:
0: Software version VISIBLE_STRING (16 bit) flags 7
13
'13'
1011:
1: SubIndex 001 UNSIGNED32 (32 bit) flags 3F
0 0
1018:
1: Vendor ID UNSIGNED32 (32 bit) flags 7
2 2
2: Product code UNSIGNED32 (32 bit) flags 7
460795986 1B773052
3: Revision UNSIGNED32 (32 bit) flags 7
1703936 1A0000
4: Serial number UNSIGNED32 (32 bit) flags 7
72315 11A7B
...
Later on, the actual functionality of the terminal is shown. As an example, a stepper motor terminal might be enabled with a boolean value, and a velocity may be set:
7010:
1: Enable BOOLEAN (1 bit) flags 47
0 0
2: Reset BOOLEAN (1 bit) flags 47
0 0
3: Reduce torque BOOLEAN (1 bit) flags 47
0 0
11: Position UNSIGNED32 (32 bit) flags 47
0 0
21: Velocity INTEGER16 (16 bit) flags 47
0 0
So in this example, CoE address 7010:21 is a 16 bit integer that sets the drive velocity of a stepper motor.
Reference Documentation¶
A collection of devices¶
This modules contains a collection of devices which may be helpful in many projects.
- class ebpfcat.devices.AnalogInput(data)¶
Generic analog input device
This device can be linked to an analog input of a terminal. It will read from there and return the result in its parameter value.
- class ebpfcat.devices.AnalogOutput(data)¶
Generic analog output device
This device can be linked to an analog output of a terminal. It will write the value to that terminal.
- class ebpfcat.devices.Counter¶
A fake device counting the loops
- class ebpfcat.devices.DigitalInput(data)¶
Generic digital input device
This device can be linked to an analog input of a terminal. It will read from there and return the result in its parameter value.
- class ebpfcat.devices.DigitalOutput(data)¶
Generic digital output device
This device can be linked to an analog output of a terminal. It will write the value to that terminal.
- class ebpfcat.devices.Dummy(terminals)¶
A placeholder device assuring a terminal is initialized
- get_terminals()¶
return the terminals used by this device
return a dictionary of terminal vs. a boolean indicating whether access is read-write.
- class ebpfcat.devices.Motor¶
A simple closed-loop motor
This device implements a closed loop between an encoder and a velocity-control motor.
- velocity: TerminalVar¶
link this to the velocity output of a motor terminal
- encoder: TerminalVar¶
link this to the position input of an encoder
- low_switch: TerminalVar¶
link to a digital input for a low limit switch
- high_switch: TerminalVar¶
link to a digital input for a high limit switch
- enable: TerminalVar¶
link to the enable parameter of the motor terminal
- current_position: TerminalVar¶
- class ebpfcat.devices.RandomDropper¶
Randomly drop packets
This fake device randomly drops EtherCat packets, to simulate bad connections.
- class ebpfcat.devices.RandomOutput(data)¶
Randomized digital output
This device randomly switches its linked digital output on or off, with a probability given by
probability
.
Low-level access to EtherCAT¶
this modules contains the code to actually talk to EtherCAT terminals.
- class ebpfcat.ethercat.CoECmd(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
- class ebpfcat.ethercat.ECCmd(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
- class ebpfcat.ethercat.ECDataType(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
- class ebpfcat.ethercat.EEPROM(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
- class ebpfcat.ethercat.EtherCat(network)¶
The EtherCAT connection
An object of this class represents one connection to an EtherCAT loop. It keeps the socket, and eventually all data flows through it.
This class supports both to send individual datagrams and wait for their response, but also to send and receive entire packets.
- async assigned_address(position)¶
return the set adress of terminal at position, if none set one
- async connect()¶
connect to the EtherCAT loop
- connection_made(transport)¶
start the send loop once the connection is made
- async count()¶
Count the number of terminals on the bus
- datagram_received(data, addr)¶
distribute received packets to the recipients
- async eeprom_read(position, start)¶
read 4 bytes from the eeprom of terminal position at start
- async find_free_address()¶
Find an absolute address not in use
an address once returned by this method is assumed to be used in the future and will never be handed out again
- async receive_index(index)¶
Wait for packet identified by index
- async roundtrip(cmd, pos, offset, *args, data=None, idx=0)¶
Send a datagram and wait for its response
- Parameters:
cmd (ECCmd) – the EtherCAT command
pos – the positional address of the terminal
offset – the offset within the terminal
idx – the EtherCAT datagram index
data – the data to be sent, or and integer for the number of zeros to be sent as placeholder
Any additional parameters will be interpreted as follows: every str is interpreted as a format for a struct.pack, everything else is the data for those format. Upon returning, the received data will be unpacked accoding to the format strings.
- async roundtrip_packet(packet)¶
Send a packet and return the response
Send the packet to the loop and wait that it comes back, and return that to the caller.
- send_packet(packet)¶
simply send the packet, fire-and-forget
- async sendloop()¶
the eternal datagram sending loop
This method runs while we are connected, takes the datagrams to be sent from a queue, packs them in a packet and ships them out.
- exception ebpfcat.ethercat.EtherCatError¶
- class ebpfcat.ethercat.MBXType(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
- class ebpfcat.ethercat.MachineState(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
The states of the EtherCAT state machine
The states are in the order in which they should be taken, BOOTSTRAP is at the end as this is a state we usually do not go to.
- class ebpfcat.ethercat.ODCmd(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
- class ebpfcat.ethercat.Packet¶
An EtherCAT packet representation
A packet contains one or more datagrams which are sent as EtherNet packets. We implicitly add a datagram in the front which later serves as an identifier for the packet.
- append(cmd, data, idx, *address)¶
Append a datagram to the packet
- Parameters:
cmd (ECCmd) – EtherCAT command
data – the data in the datagram
idx – the datagram index, unchanged by terminals
Depending on the command, one or two more parameters represent the address, either terminal and offset for position or node addressing, or one value for logical addressing.
- assemble(index)¶
Assemble the datagrams into a packet
- Parameters:
index – an identifier for the packet
An implicit empty datagram is added at the beginning of the packet that may be used as an identifier for the packet.
- full()¶
Is the data limit reached?
- class ebpfcat.ethercat.Struct(*args)¶
Define repetitive structures in CoE objects
Some terminals, especially multi-channel terminals, have repetitive structures in their CoE. Inherit from this class to create a structure for them. Each instance will then define one channel. It takes one parameter, which is the offset in the CoE address space from the template structure to the one of the channel.
- class ebpfcat.ethercat.SyncManager(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
- class ebpfcat.ethercat.Terminal(ethercat)¶
Represent one terminal (SubDevice or slave) in the loop
- async eeprom_write_one(start, data)¶
write 2 bytes to the eeprom at start
- async get_state()¶
get the current state, error flag and status word
- async initialize(relative=None, absolute=None)¶
Initialize the terminal
this sets up the connection to the terminal we represent.
- Parameters:
relative – the position of the terminal in the loop, a negative number counted down from 0 for the first terminal If None, we assume the address is already initialized
absolute – the number used to identify the terminal henceforth If None take a free one
If only one parameter is given, it is taken to be an absolute position, the terminal address is supposed to be already initialized.
This also reads the EEPROM and sets up the sync manager as defined therein. It still leaves the terminal in the init state.
- map_fmmu(logical, write)¶
map the pdo to logical address.
- Parameters:
write – a boolean indicating whether this is to be used for writing (instead of reading).
- async mbx_recv()¶
receive data from the mailbox
- async mbx_send(type, *args, data=None, address=0, priority=0, channel=0)¶
send data to the mailbox
- async read(start, *args, **kwargs)¶
read data from the terminal at offset start
see EtherCat.roundtrip for details on more parameters.
- async read_eeprom()¶
read the entire eeprom
- async read_object_entry(index, subidx)¶
read a object entry from the CoE self description
- async sdo_read(index, subindex=None)¶
read a single SDO entry
given an adress for a CoE entry like 6020:12, you may read the value like
await master.sdo_read(0x6020, 0x12)
.
- async sdo_write(data, index, subindex=None)¶
write a single SDO entry
given a CoE address like 1200:2, one may write the value as in
await master.sdo_write(b'abc', 0x1200, 0x2)
. Note that the data needs to already be a binary string matching the binary type of the parameter.
- async set_state(state)¶
try to set the state, and return the new state
- async to_operational(target=MachineState.OPERATIONAL)¶
try to bring the terminal to operational state
this tries to push the terminal through its state machine to the target state. Note that even if it reaches there, the terminal will quickly return to pre-operational if no packets are sent to keep it operational.
return the state, error flag and status before the operation.
- async write(start, *args, **kwargs)¶
write data to the terminal at offset start
see EtherCat.roundtrip for details on more parameters
The high-level API for EtherCAT loops
- class ebpfcat.ebpfcat.BaseType(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
- class ebpfcat.ebpfcat.Device¶
A device is a functional unit in an EtherCAT loop
A device aggregates data coming in and going to terminals to serve a common goal. A terminal may be used by several devices.
- get_terminals()¶
return the terminals used by this device
return a dictionary of terminal vs. a boolean indicating whether access is read-write.
- class ebpfcat.ebpfcat.DeviceVar(size='I', write=False)¶
A variable in a device for higher-level use
define a variable within a device which the device’s user can access. This is especially important for fast devices, this is the way data is communicated to and from the EBPF program.
For non-fast devices, this acts like normal Python variables.
- Parameters:
size – the size of a variable in
struct
letterswrite – whether the variable will be written to by the user
For example:
class MyDevice(Device): my_data = DeviceVar() def program(self): self.my_data = 7 device = MyDevice() print(self.my_data) # should print 7 once the program is running
- class ebpfcat.ebpfcat.EBPFTerminal(ethercat)¶
This is the base class for all supported terminal types
inheriting classes should define a
compatibility
class variable which is a set of tuples, each of which is a pair of Ethercat vendor and product id of all supported terminal types.- allocate(packet, readwrite)¶
allocate space in packet for the pdos of this terminal
return a dict that contains the datagram number and starting offset therein for each sync manager.
Negative datagram numbers are for the future FMMU datagrams.
- class ebpfcat.ebpfcat.EtherXDP(**kwargs)¶
The EtherCat packet dispatcher
This class creates an EBPF program that receives EtherCAT packet from the network and dispatches them to the sync group they belong to, or passes them on to user space if they do not belong to them.
For each sync group, there are always two packets on the wire, one that only reads value from the terminals, the other one also writes. Usually only the read-write packet is handed over to the sync group’s program. If, however, that packet gets lost, the next read-only packet is handed over.
User space is supposed to constantly feed in new packets, and the then-superfluous packets are sent back to user space. This way user space can constantly read data independent of the EBPF program. It cannot write, however, as this would cause priority issues.
- program()¶
overwrite this method with your program while subclassing
- class ebpfcat.ebpfcat.FastEtherCat(network)¶
An EtherCAT driver class for fast and slow sync groups
- async connect()¶
connect to the EtherCAT loop
- class ebpfcat.ebpfcat.FastSyncGroup(ec, devices, **kwargs)¶
- program()¶
overwrite this method with your program while subclassing
- async run()¶
attach this program to a
network
during contextattach this program to the
network
while the context manager is running, and detach it afterwards.- Parameters:
network – the name of the network interface, like
"eth0"
flags – one of the
XDPFlags
- class ebpfcat.ebpfcat.PacketDesc(sm, position, size)¶
A single value in a process data
This describes some data in the process data coming from or sent to a terminal. This is the low-level version of
ProcessDesc
, which can be used if the terminal’s self-desciption is lacking.- Parameters:
sm – the sync manager, either
SyncManager.IN
orSyncManager.OUT
.position – the byte position in the process data
size – either a
struct
definition of a data type, or an integer denoting the bit within a byte to be adressed.
- class ebpfcat.ebpfcat.PacketVar(terminal, sm, position, size)¶
- class ebpfcat.ebpfcat.ProcessDesc(index, subindex, size=None)¶
A process variable as described in the current mapping
This describes a process variable as found in the current PDO mapping read from the terminal.
- Parameters:
index – the index of the process variable, usually found in the terminal’s documentation
subindex – the subindex, also found in the documentation
size – usually the size is taken from the PDO mapping. A different size as in a
struct
definition may be given here, or the number of a bit for a bit field.
- class ebpfcat.ebpfcat.SimpleEtherCat(network)¶
- class ebpfcat.ebpfcat.SterilePacket¶
a sterile packet has all its sets exchanged by NOPs
- append(cmd, *args, counter=1)¶
Append a datagram to the packet
- Parameters:
cmd (ECCmd) – EtherCAT command
data – the data in the datagram
idx – the datagram index, unchanged by terminals
Depending on the command, one or two more parameters represent the address, either terminal and offset for position or node addressing, or one value for logical addressing.
- class ebpfcat.ebpfcat.SyncGroup(ec, devices, **kwargs)¶
A group of devices communicating at the same time
- class ebpfcat.ebpfcat.TerminalVar¶
a device variable to be linked to a process variable
Whithin a
Device
, one can refer to process variables that should later be linked to process variables of a terminal. Within the device, one can access the process variable generically. Upon instantiation one would then assign aProcessDesc
(orPacketDesc
) to it to link the variable to an actual terminal.For example:
class MyDevice(Device): the_output = TerminalVar() def program(self): self.the_output = 5 # write 5 to whatever variable linked terminal = MyTerminal() device = MyDevice() device.the_output = terminal.output5 # link the_output to output5