Giter Site home page Giter Site logo

apollo3zehn / ethercat.net Goto Github PK

View Code? Open in Web Editor NEW
167.0 16.0 52.0 161 KB

A high-level SOEM-based EtherCAT master with ESI support for Windows and Linux.

License: GNU Lesser General Public License v3.0

C# 86.70% PowerShell 0.45% CMake 0.35% C 12.50%
ethercat-master esi-files soem twincat beckhoff

ethercat.net's Introduction

EtherCAT.NET

AppVeyor NuGet

EtherCAT.NET provides high-level abstraction of the underlying native Simple Open Source EtherCAT Master (SOEM). To accomplish this, the solution contains another project: SOEM.PInvoke. It comprises the actual native libraries for Windows and Linux and allows to simply P/Invoke into the native SOEM methods. The intention is to provide a managed way to access the native SOEM master. EtherCAT.NET depends on SOEM.PInvoke and adds classes for high-level abstraction.

In its current state, many, but not all planned features are implemented. Thus, only an alpha version is available (NuGet) up to now. This mainly means that any EtherCAT network can be configured and started, but high-level features like simple configuration of the SDOs are not yet implemented.

This master already supports slave configuration via ESI files. In fact, these files are required for the master to work. As shown in the sample, you need to point the configuration to the folder, where the ESI files live.

Another feature is the configuration of complex slaves. For example, this master has been sucessfully tested with the Profibus terminal (EL6731-0010). TwinCAT allows configuration of this terminal through a special configuration page. Since creating high-level configuration interfaces for each complex slave is much work, the priority for EtherCAT.NET lies on providing a simple interface to customize SDOs (like in TwinCAT), so that the end user can tune the required settings for any slave in a generic way.

Running the application

Linux: Run the application with root privileges as pointed out here.

Windows: Install WinPcap.

How to use EtherCAT.NET

If you start with the sample, make sure to adapt the interface name in Program.cs to that of your network adapter and to populate the ESI directory with the required ESI files. When you run the sample application, the output will be similar to the following:

sample-master

Generate the list of slaves

The master can be operated without having a list of slaves. In that case, it scans available slaves during startup. But the disadvantage is that the slaves cannot be configured in advance and that no variable references are available. Therefore, there are two ways to generate the slave list as shown here:

  1. Create the list manually (it must match with the actually connected slaves)
    --> not yet possible
    
  2. Scan the list of connected slaves
    var rootSlave = EcUtilities.ScanDevices(<network interface name>);

The returned rootSlave is the master itself, which holds child slaves in its Children / Descendants property) After that, the found slaves should be populated with ESI information:

rootSlave.Descendants().ToList().ForEach(slave =>
{
    ExtensibilityHelper.CreateDynamicData(settings.EsiDirectoryPath, slave);
});
    

Accessing the slaves

This master works differently to TwinCAT in that the slaves are identified using the configure slave alias (CSA) field in the EEPROM (see section 2.3.1 of the Hardware Data Sheet Section II). Whenever the master finds a slave with CSA = 0 it assigns a new random number. This number can be acquired after the first run by printing the CSA of each slave:

var message = new StringBuilder();
var slaves = rootSlave.Descendants().ToList();

message.AppendLine($"Found {slaves.Count()} slaves:");

slaves.ForEach(current =>
{
    message.AppendLine($"{current.DynamicData.Name} (PDOs: {current.DynamicData.Pdos.Count} - CSA: { current.Csa })");
});

logger.LogInformation(message.ToString().TrimEnd());

Now, if the hardware slave order is changed, the individual slaves can be identified by:

var slaves = rootSlave.Descendants().ToList();
var EL1008 = slaves.FirstOrDefault(current => current.Csa == 3);

Of course, as long as the hardware setup does not change, you can always get a reference to a slave by simple indexing:

var EL1008 = slaves[1];

Accessing process data objects (PDOs) and variables

When you have a reference to a slave, the PDOs can be accessed via the DynamicData property:

var pdos = slaves[0].DynamicData.Pdos;
var channel0 = pdo[0];

Since a PDO is a group of variables, these can be found below the PDO:

var variables = pdo.Variables;
var variable0 = variables[0];

A variable holds a reference to a certain address in RAM. This address is found in the property variable0.DataPtr. During runtime (after configuration of the master), this address is set to a real RAM address. So the data can be manipulated using the unsafe keyword. Here we have a boolean variable, which is a single bit in EtherCAT, and it can be toggled with the following code:

unsafe
{
    var myVariableSpan = new Span<int>(variable0.DataPtr.ToPointer(), 1);
    myVariableSpan[0] ^= 1UL << variable0.BitOffset;
}

Be careful when using raw pointers, so that you do not modify data outside the array boundaries.

Running the master

First, an EcSettings object must be created. The constructor takes the parameters cycleFrequency, esiDirectoryPath and interfaceName. The first one specifies the cycle time of the master and is important for distributed clock configuration. The last one, interfaceName, is the name of your network adapter.

The esiDirectoryPath parameter contains a path to a folder containing the ESI files. For Beckhoff slaves, these can be downloaded here. The first startup may take a while since an ESI cache is built to speed-up subsequent starts. Whenever a new and unknown slave is added, this cache is rebuilt.

With the EcSettings object and a few more types (like ILogger, see the sample), the master can be put in operation using:

using (var master = new EcMaster(rootSlave, settings, extensionFactory, logger))
{
    master.Configure();

    while (true)
    {
        /* Here you can update your inputs and outputs. */
        master.UpdateIO(DateTime.UtcNow);
        /* Here you should let your master pause for a while, e.g. using Thread.Sleep or by simple spinning. */
    }
}

If you need a more sophisticated timer implementation, take a look to this one. It can be used as follows:

var interval = TimeSpan.FromMilliseconds(100);
var timeShift = TimeSpan.Zero;
var timer = new RtTimer();

using (var master = new EcMaster(settings, extensionFactory, logger))
{
    master.Configure(rootSlave);
    timer.Start(interval, timeShift, UpdateIO);

    void UpdateIO()
    {
        /* Here you can update your inputs and outputs. */
        master.UpdateIO(DateTime.UtcNow);
    }

    Console.ReadKey();
    timer.Stop();
}

Compiling the application

A single Powershell Core script is used for all platforms to initialize the solution. This simplifies CI builds - but requires Powershell Core to be available on the target system. If you don't want to install it, you can extract the information in the script and perform the steps manually.

Linux (tested on Ubuntu 18.04 x64)

You need the following tools:

The solution can then be built as follows:

  1. Execute the powershell script once within the root folder:
    pwsh ./init_solution.ps1
    
  2. Run make everytime you make changes to the native code:
    make --directory ./artifacts/bin32
    make --directory ./artifacts/bin64
    
  3. Run dotnet build everytime make changes to the managed code:
    dotnet build ./src/EtherCAT.NET/EtherCAT.NET.csproj
    
  4. Find the resulting packages in ./artifacts/packages/*.

Windows

You need the following tools:

The solution can then be built as follows:

  1. Execute the powershell script once within the root folder. If you don't want to install Powershell Core, you can adapt the script and replace $IsWindows with $true.
    ./init_solution.ps1
    
  2. Run msbuild* everytime you make changes to the native code:
    msbuild ./artifacts/bin32/SOEM_wrapper/soem_wrapper.vcxproj /p:Configuration=Release
    msbuild ./artifacts/bin64/SOEM_wrapper/soem_wrapper.vcxproj /p:Configuration=Release
    
    (* use Visual Studio Developer Command Prompt if msbuild is not available in the PATH variable or compile using Visual Studio directly).
  3. Run dotnet build everytime you make changes to the managed code:
    dotnet build ./src/EtherCAT.NET/EtherCAT.NET.csproj
    
  4. Find the resulting packages in ./artifacts/packages/*.

ethercat.net's People

Contributors

xzulux avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ethercat.net's Issues

CreateDynamicData failing to load ESI

On this ESI i'm getting this error:
startIndex cannot be larger than length of string. Parameter name: startIndex : at System.String.Substring(Int32 startIndex, Int32 length) at EtherCAT.NET.Extensibility.ExtensibilityHelper.<>c__DisplayClass0_1.<CreateDynamicData>b__1(PdoTypeEntry x) in C:\projects\ethercat-net\src\EtherCAT.NET\Extensibility\ExtensibilityHelper.cs:line 87 at System.Linq.Enumerable.WhereSelectArrayIterator2.MoveNext()
at System.Collections.Generic.List1..ctor(IEnumerable1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source) at EtherCAT.NET.Extensibility.ExtensibilityHelper.CreateDynamicData(String esiDirectoryPath, IExtensionFactory extensionFactory, SlaveInfo slaveInfo) in C:\projects\ethercat-net\src\EtherCAT.NET\Extensibility\ExtensibilityHelper.cs:line 93

Festo-CMMT-ST-CiA402-20200113.txt

ScanDevices stucks in endless loop

The adapted ScanDevices function stucks in endless loop on my current configuration. I have to investigate further to check the root cause, but it seems commit 9ad66bb Wait for PREOP before accessing EEPROM broke something on ScanDevices logic. If I revert to commit b393404 all is working as expected ... any idea?

Try catch bei SoemWrapper.RegisterCallback()

From OneDAS-Ethercat created by Apollo3zehn: OneDAS-Group/OneDAS-Ethercat#10

The callback will be executed in a different thread when CA slaves are available in the system. Exceptions cause system to crash. Bootloader.HandleException geht nicht, da keine Referenz vorhanden. Selbst wenn, wie wird dann Thread abgebrochen?

sdoWriteRequestSet.ToList().ForEach(sdoWriteRequest =>
{
EthercatStatic.CheckErrorCode(SoemWrapper.SdoWrite(slaveIndex, sdoWriteRequest.Index, sdoWriteRequest.SubIndex, sdoWriteRequest.Dataset), nameof(SoemWrapper.SdoWrite));
});

esi file xml deserialize fail

Hello, I am trying to run the sample application, But I found it occurs an error while deserializing esi file, maybe there are some differences between my esi file structure and yours, could u provide a demo esi file in sample project !

fail to compile

I tried to compile c lib in windows7 x64,but failed.
when I run init_solution.ps1
powershell shows the source directory D:/zqFile/EtherCat/Ethercat.net-master/native/soem dose not contain a cmakelists.txt file

logfile shows following error:
cl /c /Zi /W3 /WX- /diagnostics:column /Od /Ob0 /Oy- /D WIN32 /D _WINDOWS /D "CMAKE_INTDIR="Debug"" /D _MBCS /Gm- /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Zc:inline /GR /Fo"cmTC_61f26.dir\Debug\" /Fd"cmTC_61f26.dir\Debug\vc142.pdb" /Gd /TP /analyze- /errorReport:queue "C:\Program Files\CMake\share\cmake-3.19\Modules\CMakeCXXCompilerABI.cpp" CMakeCXXCompilerABI.cpp

EL6731-0010 (old version) does not start properly

From OneDAS-Ethercat created by Apollo3zehn: OneDAS-Group/OneDAS-Ethercat#15

byte[] prmData = new byte[]
{
0x80, -> 0x88
0x1,
0x14,
0xb,
0x9,
0x5f,
0x0,
0x80,
0x0,
0x8
}.Concat(userPrmData).ToArray();

context->slavelist[slaveIndex].CoEdetails == 0 although slave requires CoE (same strange behavior like EL6601?) Slave is not starting but configured exactly like TwinCAT. Maybe the reason is here also that the register upload data are wrong.

System.DllNotFoundException

System.DllNotFoundException: 'Unable to load DLL 'soem_wrapper' or one of its dependencies: The specified module could not be found.

.NET Standard 3.0.100
Visual Studio 16.3.5
Windows 10 Enterprise 1709

Output attached.
netcoreapp3.0.zip

AL Status Code 0x0050 - EEPROM No Access

Hi,

I was playing around with the sample application and run into an issue with EtherCAT slaves that need access to the SII EEPROM during the INIT->PREOP transition. The slaves are stuck in Init+Error with AL Status Code 0x0050 (EEPROM No Access).

According to ETG.1020 The EtherCAT master shall give the EEPROM access rights to the application controller [...] in the transition INIT-PREOP.

The issue seems to be in ScanDevices():

  • in ecx_config_init () PDI asscess to the EEPROM is granted before requesting PREOP: https://github.com/OpenEtherCATsociety/SOEM/blob/d9261e801d109eaf99b94907b6d24bac4a123968/soem/ethercatconfig.c#L590-L601
  • but in ScanDevices() access is immediatly taken by the master to access the Configured Station Alias(CSA):
    if (ecx_config_init(context, false) < 0)
    {
    return -0x0103;
    }
    *slaveInfoSet = (ec_slave_info_t*)calloc(*context->slavecount + 1, sizeof(ec_slave_info_t));
    *slaveCount = *context->slavecount;
    // read real CSA value from EEPROM
    for (int slaveIndex = 1; slaveIndex < *context->slavecount + 1; slaveIndex++)
    {
    ecx_eeprom2master(context, slaveIndex);
    context->slavelist[slaveIndex].aliasadr = (uint16)ecx_readeepromFP(context, context->slavelist[slaveIndex].configadr, 0x04, EC_TIMEOUTEEP);
    }

Waiting for the slaves to reach PREOP before accessing the CSA in EEPROM solves this issue.

Cheers,
Yves

SampleMaster Read PDO

I have a very simple Projekt with only one Slave (EP3174-0002 4 Channel Analog Input).
The EP is found and the Master seems to run.

The 'slaves[0].DynamicData.PdoSet[0].VariableSet' contains the different PDOs and they also get a Pointer Address to the RAM.
The 'slaves[0].DynamicData.PdoSet[0].VariableSet.Last()' is the Value.

In the 'README.md' is only how to set a single bit per unsafe.
How can I get the Value form the PDO (Pointer).
Is there a simpler way to cyclic get the input value?

PS: Is there a implementation to write slave settings with command or on 'startup'?

Remove dependency to OneDAS.

Difficult because the slave extensions totally rely on OneDAS types. Maybe it gets easier with OneDAS using Blazor instead of Typescipt.

Index 0x1600 fails but 0x1601 accepts

My slave Input SM starts at 0x1600, and on my slave software it reads 0x0016 if i don't configure variables, if i add a variable on index 0x6040 to this SM i read 0x4016 on the SM index on the slave software. If i configure the SM index to 0x1601 on the slave software it reads 0x1601 correctly.
It seams as if the 00 from 0x1600 are being removed and the byte shifted right.

How can i solve this?

Festo-CMMT-ST-CiA402-20200113.txt

Invalid watchdog configuration

Hi,

I've got a slave based on an XMC4300 and SSC which I can successfully run to OP using both TwinCAT and the SOEM simple_test.

When I run your SampleMaster switching from SAFE_OP to OP fails. If I connect to the slave again after this using the SOEM simple_test I get the error "Invalid watchdog configuration".

Apparently your SampleMaster clears the watchdog register 0x0400 (ESC_WD_DIVIDER_OFFSET), and 0x0420 (ESC_PD_WD_TIME) somewhere / somehow. I can confirm this by debugging into my firmware. The registers return zero.

I tried writing the register myself but this does not work... Any help would be appreciated.

Thanks, Maximilian

DynamicData PdoSet

How works the DynamicData?

I have a Slave (EP3174-0002) with 4 Channel.
Each channel has a Standard and a Compact PDO Setting.
In my case the lib use the Standard PDO. Why?

Is there a Parameter to detect the channel count or only by the "name" parameter?

image

image

EL6751 findings

From OneDAS-Ethercat created by Apollo3zehn: OneDAS-Group/OneDAS-Ethercat#19

  • write 1 byte variable to 0x8008: 0x1C13 contains 3x PDO
  • do not write 1 byte variable to 0x8008: 0x1C13 contains 2x PDO
  • --> terminal works in PreOp mode, but 0x1A00 is still empty!
  • EtherCAT master is able to read PDO mapping and PDO assign in PreOp mode to calculate the EtherCAT process data length

error:06070013 Data type does not match, length of service parameter too low

Hello,

i have Problem with EtherCAT Slave "PD4-EB59CD-E-65-1" (Nanotec Motor).
The ESI-File should be correct because TwinCAT3 works with it fine.

If i starte SampleMaster i get the following Messages:

===========================================================
info: EtherCAT Master[0]
Found 4 slaves:
EK1100 (PDOs: 0 - CSA: 36726)
EL2828 (PDOs: 8 - CSA: 9020)
EL7047 (PDOs: 19 - CSA: 48200)
PD4-EB59CD-E-65-1 (PDOs: 8 - CSA: 32014)
fail: EtherCAT Master[0]
SdoWrite failed (0x0000): The working counter is 0 (SOEM).

EtherCAT message:
Time:1586370400.964 SDO slave:3 index:0216.00 error:06010001 Attempt to read to a write only object

Time:1586370400.966 SDO slave:3 index:0416.00 error:06010001 Attempt to read to a write only object

Time:1586370400.971 SDO slave:3 index:031a.00 error:06010001 Attempt to read to a write only object

Time:1586370400.977 SDO slave:4 index:1a00.01 error:06070013 Data type does not match, length of service parameter too low

Time:1586370400.979 SDO slave:4 index:1a00.02 error:06070013 Data type does not match, length of service parameter too low

Time:1586370400.981 SDO slave:4 index:1a00.03 error:06070013 Data type does not match, length of service parameter too low

Time:1586370400.982 SDO slave:4 index:1a00.04 error:06070013 Data type does not match, length of service parameter too low

Time:1586370400.985 SDO slave:4 index:1a00.05 error:06070013 Data type does not match, length of service parameter too low

Time:1586370400.987 SDO slave:4 index:1a00.06 error:06070013 Data type does not match, length of service parameter too low

===========================================================

The error occurs in the following line:
In file "Program.cs"
master.Configure(rootSlaveInfo);
In File "EcMaster.cs"
this.ConfigureIoMap(slaveInfoSet);

_actualIoMapSize = EcHL.ConfigureIoMap(this.Context, _ioMapPtr, slaveRxPdoOffsetSet, slaveTxPdoOffsetSet, out _expectedWorkingCounter);

What can i do to find the reason of the error and solve the problem?

Regards

Compile on ARM (Raspberry Pi 4)

I install the compiler and change the init_solution.ps1 (remove -m32 at X86 and the 64Bit part)

Now I get this error:
`ubuntu@ubuntu:~/#Projekt/EtherCAT.NET-1.0.0-alpha.3.final$ pwsh init_solution.ps1
Updating Git submodule.
fatal: not a git repository (or any of the parent directories): .git
Creating native x86 project.

Directory: /home/ubuntu/#Projekt/EtherCAT.NET-1.0.0-alpha.3.final/artifacts

Mode LastWriteTime Length Name


d---- 03/06/2020 14:54 bin32
-- The C compiler identification is GNU 7.4.0
-- The CXX compiler identification is GNU 7.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
CMake Error at CMakeLists.txt:11 (add_subdirectory):
The source directory

/home/ubuntu/#Projekt/EtherCAT.NET-1.0.0-alpha.3.final/native/SOEM

does not contain a CMakeLists.txt file.

-- Configuring incomplete, errors occurred!
See also "/home/ubuntu/#Projekt/EtherCAT.NET-1.0.0-alpha.3.final/artifacts/bin32/CMakeFiles/CMakeOutput.log".
`

ESI CreateDynamicData (v1.0.0-alpha.4.final)

System: Windows 10 Enterprise 2016 LTSB

v1.0.0-alpha.3.final work, but with v1.0.0-alpha.4.final I get an error at CreateDynamicData

Slave:
EP2008-0002
EP3162-0002

With v1.0.0-alpha.3.final I get a DC-Shift Error:
"ConfigureDc failed (0x0302): The static drift compensation for distributed clocks failed."

Create ESI cache and remove Utilities to add new slaves more simple

From OneDAS-Ethercat created by Apollo3zehn: OneDAS-Group/OneDAS-Ethercat#24

create / rebuild .json file with SlaveID <> file name mapping by scanning all XML files in EtherCAT folder if:

  • no cache file is available
  • a cache file is there but linked ESI file is not available or searched slave is not contained in that file

do not use SQLite, it is overkill and introduces new dependency

either rebuild cache when new file was added or offer a manual cache rebuild in GUI

see also #14

make use of SoemWrapper.UploadPdoConfig (e.g. A107 or AnybusXGateway terminal)

From OneDAS-Ethercat created by Apollo3zehn: OneDAS-Group/OneDAS-Ethercat#11

The question is how to store this information, as not all PDO variations can be represented as OneDasModules.

Example for testing:

EthercatStatic.Initialize();
IntPtr context = SoemWrapper.CreateContext();
var slaveInfo = SoemWrapper.ScanDevices(context, "6805CA393A81");
SoemWrapper.UploadPdoConfig(context, 1, 0x1C13)
SoemWrapper.Free(context);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.