diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml new file mode 100644 index 00000000..074e24ae --- /dev/null +++ b/.github/workflows/documentation.yml @@ -0,0 +1,60 @@ +name: Documentation + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the master branch + push: + branches: [ main ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build_documentation: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v3 + + - name: Install dependencies + run: | + sudo apt-get update -qq + sudo apt-get install -y -qq doxygen graphviz plantuml + pip install sphinx-rtd-theme + pip install sphinxcontrib-plantuml + pip install sphinx-mdinclude + pip install breathe + pip install exhale + - name: Build doxygen + run: | + cd ./documentation/doxygen/ + doxygen + cd ../.. + - name: Build documentation + run: | + cd ./documentation/sphinx/ + make html + cd ../.. + - name: Create commit + run: | + git clone https://github.com/ICube-Robotics/ethercat_driver_ros2.git --branch gh-pages --single-branch gh-pages + mkdir -p gh-pages/docs/ + mkdir -p gh-pages/api/ + cp -r ./documentation/sphinx/_build/html/* gh-pages/ + cp -r ./documentation/doxygen/_build/html/* gh-pages/api/ + cd gh-pages + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add . + git commit -m "Update documentation" -a || true + - name: Push changes + uses: ad-m/github-push-action@master + with: + branch: gh-pages + directory: gh-pages + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index d10f6d20..c58edcbc 100644 --- a/README.md +++ b/README.md @@ -7,71 +7,7 @@ Implementation of a `Hardware Interface` for simple Ethercat module integration ## About [EtherCAT](https://www.ethercat.org/default.htm) provides applications with the capacity of reliable, real-time communication between systems and is therefore a common industrial standard. In order to simplify the development/deployment of new application using EtherCAT modules, the `ethercat_driver` allows to combine them with [`ros2_control`](https://github.com/ros-controls/ros2_control). This driver proposes a generic ways to parametrise and assemble `Hardware Interfaces` based on EtherCAT modules that can be defined using parameter files. -## Usage -### 1. Installation -Installation steps for [IgH EtherCAT Master for Linux](https://etherlab.org/en/ethercat/) and the driver can be found [here](INSTALL.md). - -### 2. Description -#### Hardwre Interfaces and EtherCAT Master -The `ethercat_driver` is designed in such a way that each EtherCAT Master is defined in `ros2_control` as a specific `Hardware Interface`. This is done in the `ros2_control` description file, where the EtherCAT driver is loaded as `Hardware Interface` and linked to an EtherCAT Master by its ID: -```xml - - - ethercat_driver/EthercatDriver - 0 - 100 - - -``` -**NOTE**: As in the current implementation of `ros2_control` there is no information about the system update frequency, it needs to be passed here as parameter. This is only needed systems that include EtherCAT modules that use the Distributed Clock. - -#### EtherCAT Slave modules as Plugins -In this driver, the EtherCAT Slave modules are defined as [Plugins](https://docs.ros.org/en/foxy/Tutorials/Pluginlib.html) and can be parametrized in the `ros2_control` description file : -```xml - - ethercat_plugins/ECModule - 0 - 1 - -``` -All modules have `alias` and `position` parameters that specify their address in the EtherCAT Bus topology. Additional parameters can be specified depending on the purpose of the module. A list of implemented modules and their parameters can be found [here](ethercat_plugins/available_plugins.md). - -#### Interfacing controllers with EtherCAT Slave modules -In `ros2_control` the access to resources within a system from a controller is done by means of [`Hardware Resources`](https://github.com/ros-controls/roadmap/blob/master/design_drafts/hardware_access.md). For this purpose `state_interface` and `command_interface` tags need to be defined and associated with the module functionalities. -Also, for better understanding of the overall system, the pupropose of the used modules need to be clearly identified and sorted into the following types: -- ``: logical component actuated by at least one actuator with read-write capacity. -- ``: logical component to read-only states from system. -- ``: logical component for general purpose IO systems. - -**NOTE**: These components have the possibility to include parameters that will be used to link particular states and commands to the slave module input/outputs. - -Here is an example of a `gpio` resource built using 2 EtherCAT IO modules, where digital commands are mapped on ports 4 and 6 of the digital output module and analog states are read from ports 1 and 4 of the analog input module: -```xml - - - - - - - - - ethercat_plugins/Beckhoff_EL3104 - 0 - 1 - ana_input.1 - ana_input.2 - - - ethercat_plugins/Beckhoff_EL2008 - 0 - 2 - dig_output.2 - dig_output.1 - - -``` - -**NOTE** : To send commands to `gpio` resources, a generic controller was developed and can be found [here](https://github.com/mcbed/ros2_controllers/tree/gpio_controllers). +**For more information, please check the [documentation](https://ICube-Robotics.github.io/ethercat_driver_ros2/).** ## Acknowledgments Parts of the driver are based on the implementation of [`SimplECAT`](https://bitbucket.org/bsoe/simplecat/src/master/). @@ -79,6 +15,6 @@ Parts of the driver are based on the implementation of [`SimplECAT`](https://bit ## Contacts ## ![icube](https://icube.unistra.fr/fileadmin/templates/DUN/icube/images/logo.png) -[ICube Laboratory](https://plateforme.icube.unistra.fr), [University of Strasbourg](https://www.unistra.fr/), France +[ICube Laboratory](https://icube.unistra.fr), [University of Strasbourg](https://www.unistra.fr/), France -__Maciej Bednarczyk:__ [m.bednarczyk@unistra.fr](mailto:m.bednarczyk@unistra.fr), @github: [mcbed](mailto:macbednarczyk@gmail.com) +__Maciej Bednarczyk:__ [m.bednarczyk@unistra.fr](mailto:m.bednarczyk@unistra.fr), @github: [mcbed](https://github.com/mcbed) diff --git a/ethercat_driver_ros2/CMakeLists.txt b/ethercat_driver_ros2/CMakeLists.txt new file mode 100644 index 00000000..f372d947 --- /dev/null +++ b/ethercat_driver_ros2/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.8) +project(ethercat_driver_ros2 NONE) +find_package(ament_cmake REQUIRED) +ament_package() diff --git a/ethercat_driver_ros2/doxygen/Doxyfile b/ethercat_driver_ros2/doxygen/Doxyfile new file mode 100644 index 00000000..7a3e19f4 --- /dev/null +++ b/ethercat_driver_ros2/doxygen/Doxyfile @@ -0,0 +1,23 @@ +# All settings not listed here will use the Doxygen default values. + +PROJECT_NAME = "ethercat_driver_ros2" +PROJECT_NUMBER = main +PROJECT_BRIEF = "C++ ROS test" + +# Use these lines to include the generated logging.hpp (update install path if needed) +INPUT = ../../ethercat_driver/include ../../ethercat_interface/include + +RECURSIVE = YES +OUTPUT_DIRECTORY = _build + +EXTRACT_ALL = YES +SORT_MEMBER_DOCS = NO + +GENERATE_LATEX = NO +GENERATE_XML = YES + +ENABLE_PREPROCESSING = YES + +DOT_GRAPH_MAX_NODES = 101 + +FILE_PATTERNS = *.cpp *.h *.hpp *.md diff --git a/ethercat_driver_ros2/package.xml b/ethercat_driver_ros2/package.xml new file mode 100644 index 00000000..b6fdf8c6 --- /dev/null +++ b/ethercat_driver_ros2/package.xml @@ -0,0 +1,18 @@ + + + + ethercat_driver_ros2 + 1.0.0 + Meta-package aggregating the ethercat_driver_ros2 packages and documentation + Maciej Bednarczyk + Apache License 2.0 + + ament_cmake + ethercat_driver + ethercat_interface + ethercat_plugins + + + ament_cmake + + diff --git a/ethercat_driver_ros2/sphinx/Makefile b/ethercat_driver_ros2/sphinx/Makefile new file mode 100644 index 00000000..7c644899 --- /dev/null +++ b/ethercat_driver_ros2/sphinx/Makefile @@ -0,0 +1,24 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile clean + +clean: + rm -rf "_doxygen/" "api/" + @$(SPHINXBUILD) -M clean "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/ethercat_driver_ros2/sphinx/_static/css/custom.css b/ethercat_driver_ros2/sphinx/_static/css/custom.css new file mode 100644 index 00000000..54d2f2e7 --- /dev/null +++ b/ethercat_driver_ros2/sphinx/_static/css/custom.css @@ -0,0 +1,17 @@ + +.wy-table-responsive table td, +.wy-table-responsive table th { + white-space:normal; +} + +tr { + white-space: normal; +} + +thead { + white-space: normal; +} + +table { + white-space: normal; +} diff --git a/ethercat_driver_ros2/sphinx/conf.py b/ethercat_driver_ros2/sphinx/conf.py new file mode 100644 index 00000000..5b6a976a --- /dev/null +++ b/ethercat_driver_ros2/sphinx/conf.py @@ -0,0 +1,100 @@ +# Copyright 2022 ICube Laboratory, University of Strasbourg +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +from pathlib import Path + +# -- Project information ----------------------------------------------------- + +project = "ethercat_driver_ros2" +copyright = "2023, ICUBE Laboratory, University of Strasbourg" +author = "Maciej Bednarczyk, Philippe Zanne, Laurent Barbé" + +# The full version, including alpha/beta/rc tags +release = "1.0.0" + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx_rtd_theme", + "sphinx_mdinclude", + "sphinx.ext.imgmath", + "sphinx.ext.todo", + "sphinx.ext.graphviz", + "sphinxcontrib.plantuml", + "breathe", +] + +breathe_default_project = "ethercat_driver_ros2" + + +def get_package(package: str): + path = Path(__file__).parent.parent.parent.joinpath(f"{package}/include/{package}") + files_gen = path.glob("*.hpp") + files = [] + for file in files_gen: + files.append(file.name) + return (path, files) + + +breathe_projects = { + "ethercat_driver_ros2": "../doxygen/_build/xml/", +} + + +# Tell sphinx what the primary language being documented is. +primary_domain = "cpp" + +# Tell sphinx what the pygments highlight language should be. +highlight_language = "cpp" + + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = "sphinx_rtd_theme" + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] +html_logo = "images/logo-icube.png" +html_css_files = ["css/custom.css"] +pygments_style = "sphinx" diff --git a/ethercat_driver_ros2/sphinx/developer_guide/cia402_drive.rst b/ethercat_driver_ros2/sphinx/developer_guide/cia402_drive.rst new file mode 100644 index 00000000..ee180445 --- /dev/null +++ b/ethercat_driver_ros2/sphinx/developer_guide/cia402_drive.rst @@ -0,0 +1,220 @@ +CANopen over EtherCAT for electrical drives +=========================================== + +CANopen also defines several device profiles by establishing standard behavior and communication objects for similar devices. In the case of electrical drives, the profile is given by the **CiA402** ("CANopen device profile for drives and motion control") norm compliant with the `IEC `_ standard that defines programming languages for programmable control systems. The CiA402 norm specifies specific objects in OD in range :code:`0x6000` to :code:`0x67fe`, what guarantees, that for a drive compatible with CiA402, typical process values such as position, velocity, or torque set-points and actual values will always be defined in the same objects with the same address regardless of the manufacturer and by such simplifies the commissioning of different drives. CIA402 also defines a state machine that corresponds to the drive’s actual operating state (:code:`Disabled`, :code:`Fault`, :code:`Switch ON`, etc.). This state machine is controlled and monitored by two mandatory PDO entries: :code:`Control Word` and :code:`Status Word`. The drive cannot be started until the state machine has been put into the appropriate state. + +The device states and possible control sequences of the drive are described by the CANopen state machine as follows: + +.. image:: https://webhelp.kollmorgen.com/kas/Content/Resources/Images/CoE%20status%20machine.png + :width: 400 + :alt: ecm_lifecycle + :align: center + +The possible drive states are : + +.. list-table:: CiA402 Drive States + :widths: 15 35 + :header-rows: 1 + + * - State + - Description + * - :code:`NOT_READY_TO_SWITCH_ON` + - The drive is not ready to switch on. The drive is in boot phase. Drive motion functions are disabled. No communication established. + * - :code:`SWITCH_ON_DISABLED` + - The drive cannot be enabled via the EtherCAT interface. Drive motion functions are disabled. + * - :code:`READY_TO_SWITCH_ON` + - The drive can be enabled. Parameters can be transferred. Power may be applied. Drive motion functions are disabled. + * - :code:`SWITCHED_ON` + - The drive is enabled but idle No fault detected. Power is enabled Drive motion functions are disabled. Parameters can be transferred. No set-points are transferred from the EtherCAT interface. + * - :code:`OPERATION_ENABLED` + - Normal operation mode No fault detected. Drive motion functions and power are enabled. Power enabled. Set-points are transferred from the EtherCAT interface. + * - :code:`QUICK_STOP_ACTIVE` + - The quick stop process is executed. Drive motion functions are disabled. Power is enabled. + * - :code:`FAULT_REACTION_ACTIVE` + - A fault has occurred, fault reaction processes are executed. + * - :code:`FAULT` + - A fault is active, Drive is stopped and its functions are disabled. + +State transitions are the result of events that can be either internal or triggers through the :code:`Control Word`. When a command trigger for state change is received, the transition is performed before any other command is processed. + +The possible transition states, their trigger events and performed actions are : + +.. list-table:: CiA402 Drive State Transitions + :widths: 1 20 24 + :header-rows: 1 + + * - State Transition + - Event + - Action + * - :code:`0` + - **Automatic transition** after power-on or reset application + - Drive device self-test and/or self initialization has to be performed + * - :code:`1` + - **Automatic transition** + - Communication has to be activated + * - :code:`2` + - Shutdown command from control device or local signal + - None + * - :code:`3` + - Switch on command received from control device or local signal + - The high-level power has to be switched ON, if possible + * - :code:`4` + - Enable operation command received from control device or local signal + - The drive function has to be enabled. All internal set-points cleared. + * - :code:`5` + - Disable operation command received from control device or local signal + - The drive function has to be disabled. + * - :code:`6` + - Shutdown command received from control device or local signal + - The high-level power has to be switched OFF, if possible. + * - :code:`7` + - Quick stop or disable voltage command from control device or local signal + - None + * - :code:`8` + - Shutdown command from control device or local signal + - The drive function has to be disabled. The high-level power has to be switched OFF, if possible. + * - :code:`9` + - Disable voltage command from control device or local signal + - The drive function has to be disabled. The high-level power has to be switched OFF, if possible. + * - :code:`10` + - Disable voltage or quick stop command from control device or local signal + - The high-level power has to be switched OFF, if possible. + * - :code:`11` + - Quick stop command from control device or local signal + - The quick stop function has to be started. + * - :code:`12` + - Either: - **Automatic transition** when the quick stop function is completed and quick stop option code is 1, 2, 3 or 4. - Disable voltage command received from control device (depends on the quick stop option code) + - The drive function has to be disabled. The high-level power has to be switched OFF, if possible. + * - :code:`13` + - Fault signal + - The configured fault reaction function has to be executed. + * - :code:`14` + - **Automatic transition** + - The drive function has to be disabled. The high-level power has to be switched OFF, if possible. + * - :code:`15` + - Fault reset command from control device or local signal. + - A reset of the fault condition is performed if no fault exists currently on the drive device. After leaving the Fault state, the Fault reset bit in the control word has to be cleared by the control device. + * - :code:`16` + - If the quick stop option code is 5, 6, 7, or 8, enable operation command from control device + - The drive function has to be enabled + +CANopen uses 16-bits :code:`Status Word` and :code:`Control Word` to monitor and control the state machine. These PDO entries have the following bit assignment : + +.. list-table:: CiA402 Drive Words + :widths: 1 20 24 + :header-rows: 1 + + * - Bit + - :code:`Status Word` Name + - :code:`Control Word` Name + * - :code:`0` + - Ready to switch on + - Switch On + * - :code:`1` + - Switched on + - Disable Voltage + * - :code:`2` + - Operation Enabled + - Quick Stop + * - :code:`3` + - Fault + - Enable Operation + * - :code:`4` + - Voltage Enabled + - Operation-mode Specific + * - :code:`5` + - Quick Stop + - Operation-mode Specific + * - :code:`6` + - Switch On Disabled + - Operation-mode Specific + * - :code:`7` + - Warning + - Reset Fault (only effective for faults) + * - :code:`8` + - Manufacturer-specific (reserved) + - Pause/halt + * - :code:`9` + - Remote (always 1) + - Reserved + * - :code:`10` + - Target Reached + - Reserved + * - :code:`11` + - Internal Limit Active + - Reserved + * - :code:`12` + - Operation-mode Specific (reserved) + - Reserved + * - :code:`13` + - Operation-mode Specific (reserved) + - Manufacturer-specific + * - :code:`14` + - Manufacturer-specific (reserved) + - Manufacturer-specific + * - :code:`15` + - Manufacturer-specific (reserved) + - Manufacturer-specific + +.. image:: https://infosys.beckhoff.com/content/1033/ax2000-b110/Images/StateMachine04.gif + :width: 700 + :alt: words + +The :code:`Status Word` is only updated and written by the drive in :code:`Safe-Op` and :code:`Operational` states. The current drive state can be decoded from the logical combination of the bits in the :code:`Status Word`: + +.. list-table:: CiA402 Drive State form :code:`Status Word` + :widths: 50 50 + :header-rows: 1 + + * - :code:`Status Word` + - State + * - :code:`xxxx xxxx x0xx 0000` + - Not ready to switch on + * - :code:`xxxx xxxx x1xx 0000` + - Switch on disabled + * - :code:`xxxx xxxx x01x 0001` + - Ready to switch on + * - :code:`xxxx xxxx x01x 0011` + - Switched on + * - :code:`xxxx xxxx x01x 0111` + - Operation enabled + * - :code:`xxxx xxxx x00x 0111` + - Quick stop active + * - :code:`xxxx xxxx x0xx 1111` + - Fault reaction active + * - :code:`xxxx xxxx x0xx 1000` + - Fault + +The control commands allow the manipulation of the state of a drive by setting its control word. Commands are built up from the logical combination of the bits in the :code:`Control Word`: + +.. list-table:: CiA402 Drive Commands to :code:`Control Word` + :widths: 25 25 25 + :header-rows: 1 + + * - :code:`Control Word` + - Command + - State Transitions + * - :code:`xxxx 0xxx x110` + - Shutdown + - 2, 6, 8 + * - :code:`xxxx 0xxx 0111` + - Switch On + - 3 + * - :code:`xxxx 0xxx 1111` + - Switch On + Enable Operation + - 3 + 4 + * - :code:`xxxx 0xxx xx0x` + - Disable + - 7, 9, 10, 12 + * - :code:`xxxx 0xxx x01x` + - Quick Stop + - 7, 10, 11 + * - :code:`xxxx 0xxx 0111` + - Disable Operation + - 5 + * - :code:`xxxx 0xxx 1111` + - Enable Operation + - 4, 16 + * - :code:`xxxx 1xxx xxxx` + - Fault Reset + - 15 diff --git a/ethercat_driver_ros2/sphinx/developer_guide/coe.rst b/ethercat_driver_ros2/sphinx/developer_guide/coe.rst new file mode 100644 index 00000000..c1b745ad --- /dev/null +++ b/ethercat_driver_ros2/sphinx/developer_guide/coe.rst @@ -0,0 +1,37 @@ +CANopen over EtherCAT +===================== + +The CANopen over EtherCAT (CoE) protocol allows devices equipped with CANopen to be used on EtherCAT-based Industrial Ethernet networks. + +CANopen +------- + +CANopen is a communication protocol based on the `CAN (Controller Area Network) `_ physical communication standard. In the `OSI communication model `_, CAN specifies the physical and data link layers, while CANopen addresses the higher layers — network, transport, session, presentation, and application. + +The CANopen protocol defines how automation devices are configured and accessed, and how messages are exchanged between them. CANopen is object-based, meaning that each node (drives, controllers, encoders, I/O, and other devices) in the network has an Object Dictionary (OD), which contains communication objects. These communication objects cover network management data; special functions; acyclic configuration data, which is handled by Service Data Objects (SDOs); cyclic real-time data, which is handled by Process Data Objects (PDOs): + +- **Process Data Objects (PDO)** contain OD entries that are cyclically transferred as process variables. Before cyclic communication is started during the configuration phase, particular OD objects are mapped to this structure. Each PDO entry has a defined offset in the exchanged dataset, encapsulated in the Ethernet frame, so that, during the cyclic phase, the slaves’ hardware can locate the relevant data. After cyclic communication is started, PDO entries are exchanged between master and slaves in every cycle and cannot be changed without reconfiguring the communication configuration of the network. +- **Service Data Objects (SDO)** contain object dictionary entries that can be exchanged acyclically. SDO works as a mailbox sending and buffering received data. This communication is acyclic and is dependent on available bandwidth in the communication cycle. This communication is not deterministic and is best suited for transmitting configuration data. + +The use of object dictionaries, Service Data Objects, and Process Data Objects is a key component of the CANopen protocol, with SDOs being the mechanism for read-write access to the object dictionary. + +Every entry of the OD objects is given an index address and sometimes a sub-index sub-address and each OD object consists of 16-bits and data indexes. In this context, addresses between :code:`0x1000` and :code:`0x1fff` contain communication objects, between :code:`0x2000` and :code:`0x5999` manufacturer specific objects and from :code:`0x6000` device profile objects. + +CANopen is widely used thanks to its low hardware cost, wide range of device and application profiles, and simple implementation. It’s also extremely reliable and provides real-time communication, making it suitable for industrial applications. + +EtherCAT +-------- + +EtherCAT is an Industrial Ethernet network. It’s based on standard Ethernet hardware but uses a “processing-on-the-fly” method for transporting and routing messages. In addition to being a real-time networking protocol, EtherCAT is deterministic, meaning it guarantees that a message will be transmitted (or an event will occur) in a specified, predictable period of time — not slower or faster. EtherCAT allows up to 100 meters between nodes (devices) and can provide data transmission rates up to 100 Mbps, with cycle times of less than 100 μs and extremely low jitter, thanks to distributed synchronized clocks. + +CANopen over EtherCAT (CoE) protocol +------------------------------------ + +CANopen over EtherCAT (CoE) allows the CANopen communication protocol to be implemented over an EtherCAT network, providing a user-friendly, cost-effective solution that provides deterministic data delivery along with faster transmission speeds over longer network lengths. + +The use of CANopen over EtherCAT is possible in significant part because EtherCAT implements the same communication system, including object dictionaries, SDOs (the SDO protocol is implemented directly from CANopen, without changes) and PDOs. And on an EtherCAT network, PDO frames are sent deterministically and without the 8-byte limit imposed by CANopen. CANopen over EtherCAT also supports the CANopen device profiles, which specify the parameters and behavior of the device, as well as the device class-specific state machines. + +.. image:: https://b2600047.smushcdn.com/2600047/wp-content/uploads/2021/12/Applied-Motion-CANopen-over-EtherCAT.png + :width: 400 + :alt: coe + :align: center diff --git a/ethercat_driver_ros2/sphinx/developer_guide/new_plugin.rst b/ethercat_driver_ros2/sphinx/developer_guide/new_plugin.rst new file mode 100644 index 00000000..145550cd --- /dev/null +++ b/ethercat_driver_ros2/sphinx/developer_guide/new_plugin.rst @@ -0,0 +1,166 @@ +Creating a new device driver +============================ + +Creating a new device driver to work with the :code:`ethercat_driver_ros2` is fairly easy. You should do this if you need to create a driver for a specific device or a specific device profile that is not yet supported. If you create a driver for a device profile we are happy to integrate the package into this repository - simply create a PR. + +What you need to do +------------------- + +To create a dedicated driver for an EtherCAT module, you need to create a new package containing the module driver plugin and register it so that it can be called by the :code:`ethercat_driver_ros2`. + +How to do it +------------ + +Create a package +~~~~~~~~~~~~~~~~ + +Create a new package using the standard ros2 pkg commands. Make sure you add the following dependencies: + +* :code:`ethercat_interface` +* :code:`pluginlib` + +Create your plugin class +~~~~~~~~~~~~~~~~~~~~~~~~ + +To be loaded by the :code:`ethercat_driver_ros2`, the new module plugin needs to inherit from the :code:`EcSlave` class and implement some of its virtual functions. To do so create in your package :code:`src` folder a new file :code:`my_ec_device_driver.cpp`: + +.. code-block:: cpp + + #include "ethercat_interface/ec_slave.hpp" + + namespace ethercat_plugins + { + + class MyEcDeviceDriver : public ethercat_interface::EcSlave + { + public: + MyEcDeviceDriver() + : EcSlave(, ) {} + virtual ~MyEcDeviceDriver() {} + // data processing method that will be called cyclically for every channel + // the index corresponds to the values registered in domains_ + virtual void processData(size_t index, uint8_t * domain_address) + { + // Your process data logic goes here + } + virtual const ec_sync_info_t * syncs() {return &syncs_[0];} + virtual size_t syncSize() + { + return sizeof(syncs_) / sizeof(ec_sync_info_t); + } + virtual const ec_pdo_entry_info_t * channels() + { + return channels_; + } + virtual void domains(DomainMap & domains) const + { + domains = domains_; + } + // configure the slave module with urdf parameters + // and link ros2_control command and stat interface + virtual bool setupSlave( + std::unordered_map slave_paramters, + std::vector * state_interface, + std::vector * command_interface) + { + state_interface_ptr_ = state_interface; + command_interface_ptr_ = command_interface; + paramters_ = slave_paramters; + + // Your module setup logic goes here + + return true; + } + + private: + // configure module channels + ec_pdo_entry_info_t channels_[X] = { + {, , }, + }; + // configure module pdos + ec_pdo_info_t pdos_[X] = { + {, , }, + }; + // configure module syncs + ec_sync_info_t syncs_[X] = { + {, , , , }, + {0xff} + }; + // configure module domain + DomainMap domains_ = { + {0, {0}} // index of channels that should call processData() + }; + }; + + } // namespace ethercat_plugins + + #include + + PLUGINLIB_EXPORT_CLASS(ethercat_plugins::MyEcDeviceDriver, ethercat_interface::EcSlave) + +Export your plugin +~~~~~~~~~~~~~~~~~~ + +In the package root directory create a plugin description file :code:`ethercat_plugins.xml` : + +.. code-block:: xml + + + + Description of the device driver. + + + +Modify your :code:`CMakeLists.txt` file so that it looks like this: + +.. code-block:: cmake + + cmake_minimum_required(VERSION 3.8) + project() + + if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) + endif() + + # find dependencies + find_package(ament_cmake REQUIRED) + find_package(ament_cmake_ros REQUIRED) + find_package(ethercat_interface REQUIRED) + find_package(pluginlib REQUIRED) + + file(GLOB_RECURSE PLUGINS_SRC src/*.cpp) + add_library(${PROJECT_NAME} ${PLUGINS_SRC}) + target_compile_features(${PROJECT_NAME} PUBLIC c_std_99 cxx_std_17) # Require C99 and C++17 + target_include_directories(${PROJECT_NAME} PUBLIC + $ + $ + ) + ament_target_dependencies( + ${PROJECT_NAME} + "ethercat_interface" + "pluginlib" + ) + pluginlib_export_plugin_description_file(ethercat_interface ethercat_plugins.xml) + install( + DIRECTORY include/ + DESTINATION include + ) + install( + TARGETS ${PROJECT_NAME} + EXPORT export_${PROJECT_NAME} + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin + ) + ament_export_include_directories( + include + ) + ament_export_libraries( + ethercat_plugins + ) + ament_export_targets( + export_${PROJECT_NAME} + ) + ament_package() diff --git a/ethercat_driver_ros2/sphinx/images/logo-icube.png b/ethercat_driver_ros2/sphinx/images/logo-icube.png new file mode 100644 index 00000000..cf22f48a Binary files /dev/null and b/ethercat_driver_ros2/sphinx/images/logo-icube.png differ diff --git a/ethercat_driver_ros2/sphinx/index.rst b/ethercat_driver_ros2/sphinx/index.rst new file mode 100644 index 00000000..b7017911 --- /dev/null +++ b/ethercat_driver_ros2/sphinx/index.rst @@ -0,0 +1,31 @@ +EtherCAT Driver ROS2 Stack +========================== + +`EtherCAT `_ provides applications with the capacity of reliable, real-time communication between systems and is therefore a common industrial standard. In order to simplify the development/deployment of new application using EtherCAT modules, this stack allows to combine them with `ros2_control `_. This driver proposes a generic ways to parametrize and assemble Hardware Interfaces based on EtherCAT modules that can be defined using parameter files. + +.. toctree:: + :maxdepth: 1 + :caption: Quickstart + :glob: + + quickstart/installation + quickstart/configuration + quickstart/usage + +.. toctree:: + :maxdepth: 1 + :caption: User Guide + :glob: + + user_guide/config_generic_slave + user_guide/config_cia402_drive + +.. toctree:: + :maxdepth: 1 + :caption: Developer Guide + :glob: + + developer_guide/coe + developer_guide/cia402_drive + developer_guide/new_plugin + API Reference diff --git a/ethercat_driver_ros2/sphinx/make.bat b/ethercat_driver_ros2/sphinx/make.bat new file mode 100644 index 00000000..8084272b --- /dev/null +++ b/ethercat_driver_ros2/sphinx/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/ethercat_driver_ros2/sphinx/quickstart/configuration.rst b/ethercat_driver_ros2/sphinx/quickstart/configuration.rst new file mode 100644 index 00000000..35aff5a3 --- /dev/null +++ b/ethercat_driver_ros2/sphinx/quickstart/configuration.rst @@ -0,0 +1,76 @@ +Configuration +============= + +Hardware Interfaces and EtherCAT Master +--------------------------------------- + +The EtherCAT Driver is designed in such a way that each EtherCAT Master is defined in :code:`ros2_control` as a specific Hardware Interface. This is done in the :code:`ros2_control` description file, where the EtherCAT driver is loaded as Hardware Interface and linked to an EtherCAT Master by its ID: + +.. code-block:: xml + + + + ethercat_driver/EthercatDriver + 0 + 100 + + + +.. note:: As in the current implementation of :code:`ros2_control` there is no information about the system update frequency, it needs to be passed here as parameter. This is only needed by systems that include EtherCAT modules that use the Distributed Clock. + +EtherCAT Slave modules as Plugins +--------------------------------- + +In this driver, the EtherCAT Slave modules are defined as `Plugins `_ and can be parametrized in the :code:`ros2_control` description file : + +.. code-block:: xml + + + ethercat_plugins/ECModule + 0 + 1 + + +.. note:: All modules have :code:`alias` and :code:`position` parameters that specify their address in the EtherCAT Bus topology. Additional parameters can be specified depending on the purpose of the module. + +EtherCAT Slave module plugins come in two version: + +* **Generic plugins** : generic module implementation configured using a configuration file which purpose is to facilitate the use of generally available devices. For most applications, the use of these plugins is encouraged. +* **Specific plugins** : specific implementations for dedicated devices or dedicated functionalities. + +.. note:: A list of implemented specific plugins for EtherCAT modules and their parameters can be found in this list of `available plugins `_. + +Creating components with EtherCAT Slave modules +----------------------------------------------- + +In :code:`ros2_control` the access to resources within a system from a controller is done by means of `Hardware Resources `_. For this purpose :code:`state_interface` and :code:`command_interface` tags need to be defined and associated with the module functionalities. +Also, for better understanding of the overall system, the purpose of the used modules need to be clearly identified and sorted into the following types: + +* :code:``: logical component actuated by at least one actuator with read-write capacity. +* :code:``: logical component to read-only states from system. +* :code:``: logical component for general purpose IO systems. + +Here is an example of a :code:`gpio` resource built using 2 EtherCAT IO modules: + +.. code-block:: xml + + + + + + + + ethercat_generic_plugins/GenericEcSlave + 0 + 0 + /path/to/EL3104_slave_config.yaml + + + ethercat_generic_plugins/GenericEcSlave + 0 + 1 + /path/to/EL2008_slave_config.yaml + + + +.. note:: To send commands to :code:`gpio` resources, a generic controller was developed and can be found on this `branch `_. diff --git a/ethercat_driver_ros2/sphinx/quickstart/installation.rst b/ethercat_driver_ros2/sphinx/quickstart/installation.rst new file mode 100644 index 00000000..93b176b1 --- /dev/null +++ b/ethercat_driver_ros2/sphinx/quickstart/installation.rst @@ -0,0 +1,140 @@ +Installation +=============================== + +**Required setup : Ubuntu 22.04 LTS** + +Installing EtherLab +------------------- +The proposed development builds upon the `IgH EtherCAT Master `_. +Installation steps are summarized here: + +* Install required tools: + + .. code-block:: console + + $ sudo apt-get update + $ sudo apt-get upgrade + $ sudo apt-get install git autoconf libtool pkg-config make build-essential net-tools + +* Setup sources for the EtherCAT Master: + + .. code-block:: console + + $ git clone https://gitlab.com/etherlab.org/ethercat.git + $ cd ethercat + $ git checkout stable-1.5 + $ sudo rm /usr/bin/ethercat + $ sudo rm /etc/init.d/ethercat + $ ./bootstrap # to create the configure script + +* Configure, build and install libs and kernel modules: + + .. code-block:: console + + $ ./configure --prefix=/usr/local/etherlab --disable-8139too --disable-eoe --enable-generic + + $ make all modules + $ sudo make modules_install install + $ sudo depmod + + .. note:: This step is needed every time the Linux kernel is updated. +* Configure system: + + .. code-block:: console + + $ sudo ln -s /usr/local/etherlab/bin/ethercat /usr/bin/ + $ sudo ln -s /usr/local/etherlab/etc/init.d/ethercat /etc/init.d/ethercat + $ sudo mkdir -p /etc/sysconfig + $ sudo cp /usr/local/etherlab/etc/sysconfig/ethercat /etc/sysconfig/ethercat + +* Create a new :code:`udev` rule: + + .. code-block:: console + + $ sudo gedit /etc/udev/rules.d/99-EtherCAT.rules + + containing: + + .. code-block:: console + + KERNEL=="EtherCAT[0-9]*", MODE="0666" + + +* Configure the network adapter for EtherCAT: + + .. code-block:: console + + $ sudo gedit /etc/sysconfig/ethercat_driver_ros2 + + In the configuration file specify the mac address of the network card to be used and its driver + + .. code-block:: console + + MASTER0_DEVICE="ff:ff:ff:ff:ff:ff" # mac address + DEVICE_MODULES="generic" + +Now you can start the EtherCAT master: + +.. code-block:: console + + $ sudo /etc/init.d/ethercat start + +it should print + +.. code-block:: console + + Starting EtherCAT master 1.5.2 done + + +You can check connected slaves: + +.. code-block:: console + + $ ethercat slaves + +It should print information of connected slave device: + +.. code-block:: console + + : + + +Example: + +.. code-block:: console + + 0 0:0 PREOP + + 0 0:1 PREOP + + +Building :code:`ethercat_driver_ros2` +------------------------------------- + +1. Install ROS2 packages. The current development is based of :code:`ros2 humble`. Installation steps are described in the `ROS2 Humble Documentation `_. +2. Source your ROS2` environment: + + .. code-block:: console + + source /opt/ros/humble/setup.bash + + .. note:: The ROS2 environment needs to be sources in every used terminal. If only one distribution of ROS2 is used, it can be added to the :code:`~/.bashrc` file. + +3. Install :code:`colcon` and its extensions : + + .. code-block:: console + + sudo apt install python3-colcon-common-extensions + +4. Create a new ROS2 workspace: + + .. code-block:: console + + mkdir ~/ros2_ws/src + +5. Pull relevant packages, install dependencies, compile, and source the workspace by using: + + .. code-block:: console + + cd ~/ros2_ws + git clone https://github.com/ICube-Robotics/ethercat_driver_ros2.git src/ethercat_driver_ros2 + rosdep install --ignore-src --from-paths . -y -r + colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release --symlink-install + source install/setup.bash diff --git a/ethercat_driver_ros2/sphinx/quickstart/usage.rst b/ethercat_driver_ros2/sphinx/quickstart/usage.rst new file mode 100644 index 00000000..e1605b3e --- /dev/null +++ b/ethercat_driver_ros2/sphinx/quickstart/usage.rst @@ -0,0 +1,40 @@ +Usage +===== + +Start EtherCAT Master +--------------------- + +First start the EtherCAT Master + +.. code-block:: console + + $ sudo /etc/init.d/ethercat start + +it should print + +.. code-block:: console + + Starting EtherCAT master 1.5.2 done + +You can check connected slaves: + +.. code-block:: console + + $ ethercat slaves + +It should print information of connected slave device: + +.. code-block:: console + + : + + +.. note:: If nothing is displayed or some slave modules are missing, it means that your EtherCAT Master is either not well configured, or that the connection on your field-bus is interrupted. + +Launch configuration +-------------------- + +Once the EtherCAT Master is running you can go on and launch your configuration package. + +.. code-block:: console + + $ ros2 launch [package] [launchfile] diff --git a/ethercat_driver_ros2/sphinx/user_guide/config_cia402_drive.rst b/ethercat_driver_ros2/sphinx/user_guide/config_cia402_drive.rst new file mode 100644 index 00000000..b12fc98d --- /dev/null +++ b/ethercat_driver_ros2/sphinx/user_guide/config_cia402_drive.rst @@ -0,0 +1,104 @@ +CiA402 EtherCAT Motor Drive configuration +========================================= + +The generic plugin :code:`EcCiA402Drive` is a particular case of the :code:`GenericEcSlave` enabling features compliant with the CiA402 (“CANopen device profile for drives and motion control”) norm. Therefore, the configuration of such a drive uses the same formalism for the :code:`slave_config` file as in the case of the :code:`GenericEcSlave`. + +Plugin features +--------------- + +* **Drive State transitions**: Management of the motor drive states and their transitions. +* **Drive Fault reset**: Management of the motor drive fault reset using :code:`command_interface` "reset_fault". +* **Mode of Operation**: Management of multiple cyclic modes of operation : position (8), velocity (9), effort (10) and homing (6) with the possibility of switch between them. +* **Default position**: Management of the target position when not controlled. + +Configuration options +--------------------- + +In addition to the configuration options given by the :code:`GenericEcSlave`, the :code:`EcCiA402Drive` allows to configure the following options in the :code:`slave_config` file: + +.. list-table:: + :widths: 15 35 + :header-rows: 1 + + * - Configuration flag + - Description + * - :code:`auto_fault_reset` + - if set to :code:`true` the drive performs automatic fault reset; if set to :code:`false`, fault reset is only performed on rising edge (0 -> 1) command on the :code:`command_interface` "reset_fault". + +Behavior +-------- +Here are some remarks about the implemented motor drive behavior logic. + +After launching the well-configured drive, by default and without fault, motor drive module is brought automatically into the state :code:`OPERATION_ENABLED` making it ready for use. Automatic transition is only enabled when the :code:`control_word` command interface is either missing or set to :code:`NaN` making it possible for the user to take control over the motor drive's state machine by sending corresponding state transition values using the :code:`control_word` command interface. + +The default mode of operation of the motor drive can be set either in the configuration yaml file as the default value of the corresponding PDO channel or in urdf using the :code:`mode_of_operation` parameter of the the :code:`EcCiA402Drive`. If both are set, the urdf parameter value overrides the default one from the configuration yaml file. + +In order to prevent unwanted movements of the motor, if uncontrolled, the default target position that is send to the drive in all modes of operation is always the last read position. That is why, it is important to send :code:`NaN` in the position command interface when not controlling the motor position. This applies especially for cases when switching between modes. + +Usage +----- + +Example configuration for the Maxon EPOS3 motor dive: + +.. code-block:: yaml + + # Configuration file for Maxon EPOS3 drive + vendor_id: 0x000000fb + product_id: 0x64400000 + assign_activate: 0x0300 # DC Synch register + auto_fault_reset: false # true = automatic fault reset, false = fault reset on rising edge command interface "reset_fault" + sdo: # sdo data to be transferred at drive startup + - {index: 0x60C2, sub_index: 1, type: int8, value: 10} # Set interpolation time for cyclic modes to 10 ms + - {index: 0x60C2, sub_index: 2, type: int8, value: -3} # Set base 10-3s + rpdo: # RxPDO = receive PDO Mapping + - index: 0x1603 + channels: + - {index: 0x6040, sub_index: 0, type: uint16, default: 0} # Control word + - {index: 0x607a, sub_index: 0, type: int32, command_interface: position, default: .nan} # Target position + - {index: 0x60ff, sub_index: 0, type: int32, default: 0} # Target velocity + - {index: 0x6071, sub_index: 0, type: int16, default: 0} # Target torque + - {index: 0x60b0, sub_index: 0, type: int32, default: 0} # Offset position + - {index: 0x60b1, sub_index: 0, type: int32, default: 0} # Offset velocity + - {index: 0x60b2, sub_index: 0, type: int16, default: 0} # Offset torque + - {index: 0x6060, sub_index: 0, type: int8, default: 8} # Mode of operation + - {index: 0x2078, sub_index: 1, type: uint16, default: 0} # Digital Output Functionalities + - {index: 0x60b8, sub_index: 0, type: uint16, default: 0} # Touch Probe Function + tpdo: # TxPDO = transmit PDO Mapping + - index: 0x1a03 + channels: + - {index: 0x6041, sub_index: 0, type: uint16} # Status word + - {index: 0x6064, sub_index: 0, type: int32, state_interface: position} # Position actual value + - {index: 0x606c, sub_index: 0, type: int32, state_interface: velocity} # Velocity actual value + - {index: 0x6077, sub_index: 0, type: int16, state_interface: effort} # Torque actual value + - {index: 0x6061, sub_index: 0, type: int8} # Mode of operation display + - {index: 0x2071, sub_index: 1, type: int16} # Digital Input Functionalities State + - {index: 0x60b9, sub_index: 0, type: int16} # Touch Probe Status + - {index: 0x60ba, sub_index: 0, type: int32} # Touch Probe Position 1 Positive Value + - {index: 0x60bb, sub_index: 0, type: int32} # Touch Probe Position 1 Negative Value + +This configuration can be used for controlling a :code:`joint` component. Here is an example urdf for :code:`ros2_control` using this configuration together with the :code:`EcCiA402Drive` plugin: + +.. code-block:: xml + + + + ethercat_driver/EthercatDriver + 0 + 100 + + + + + + + + + + ethercat_generic_plugins/EcCiA402Drive + 0 + 0 + 8 + /path/to/maxon.yaml + + + diff --git a/ethercat_driver_ros2/sphinx/user_guide/config_generic_slave.rst b/ethercat_driver_ros2/sphinx/user_guide/config_generic_slave.rst new file mode 100644 index 00000000..c426c513 --- /dev/null +++ b/ethercat_driver_ros2/sphinx/user_guide/config_generic_slave.rst @@ -0,0 +1,217 @@ +Generic EtherCAT Slave configuration +==================================== + +Configuration options +--------------------- + +The :code:`GenericEcSlave` allows to configure the following options in the :code:`slave_config` file: + +.. list-table:: + :widths: 15 35 + :header-rows: 1 + + * - Configuration flag + - Description + * - :code:`vendor_id` + - Vendor identification number in hexadecimal format :code:`0x...`. + * - :code:`product_id` + - Product identification number in hexadecimal format :code:`0x...`. + * - :code:`assign_activate` + - Distributed Clock Synchronization register in hexadecimal format :code:`0x...`. If not used remove or set to :code:`0x00`. + * - :code:`sdo` + - SDO data to be transferred at drive startup for configuration purposes. + * - :code:`tpdo` + - Transmit PDO mapping configuration. + * - :code:`rpdo` + - Receive PDO mapping configuration. + * - :code:`sm` + - Sync Manager configuration. + +SDO configuration +~~~~~~~~~~~~~~~~~ + +Service Data Objects (SDO) are used to setup the module at startup. This is done only one during the activation phase. +Each SDO has the following configuration flags: + +.. list-table:: + :widths: 15 35 + :header-rows: 1 + + * - SDO flag + - Description + * - :code:`index` + - SDO index in hexadecimal format :code:`0x...`. + * - :code:`sub_index` + - SDO sub-index in hexadecimal format :code:`0x...`. + * - :code:`type` + - SDO data type. Possible types: :code:`bool`, :code:`uint8`, :code:`int8`, :code:`uint16`, :code:`int16`, :code:`uint32`, :code:`uint32`, :code:`uint64`, :code:`uint64`, :code:`bitN` with N the number of bits required. + * - :code:`value` + - Value to be transferred to the module. + +PDO mapping configuration +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :code:`tpdo` and :code:`rpdo` Process Data Object (PDO) mapping configurations can be composed of multiple PDO mappings. +Each PDO mapping requires to specify its register :code:`index` and the configuration of the PDO Channels it is composed of. + +PDO channel configuration +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Each PDO Channel has the following configuration flags: + +.. list-table:: + :widths: 15 35 + :header-rows: 1 + + * - PDO Channel flag + - Description + * - :code:`index` + - Channel index in hexadecimal format :code:`0x...`. + * - :code:`sub_index` + - Channel sub-index in hexadecimal format :code:`0x...`. + * - :code:`type` + - Channel data type. Possible types: :code:`bool`, :code:`uint8`, :code:`int8`, :code:`uint16`, :code:`int16`, :code:`uint32`, :code:`uint32`, :code:`uint64`, :code:`uint64`, :code:`bitN` with N the number of bits required. + * - :code:`command_interface` + - **Only for** :code:`tpdo`. Name of the command interface to be used inside :code:`ros2_control`. + * - :code:`state_interface` + - **Only for** :code:`rpdo`. Name of the state interface to be used inside :code:`ros2_control`. + * - :code:`default` + - **Only for** :code:`tpdo`. Default value to be send to the drive if data received on the command interface is :code:`NaN`. + * - :code:`mask` + - Data mask, to be used with :code:`type` = :code:`bool`. + * - :code:`factor` + - Data conversion factor. + * - :code:`offset` + - Data offset term. + + +.. warning:: For each channel, tags :code:`index`, :code:`sub_index` and :code:`type` are **mandatory** even if the channel is not used in order to fill the data layout expected by the module. All other tags can remain unset. +.. note:: Data type :code:`bitN` is used for gaps in the config. Refer to module manual if required. +.. note:: Data type :code:`bool` requires the use of the :code:`mask` option as the registers can only be read as a multiple of 8 bits. + +Sync Manager Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A SyncManager protects a DPRAM area from simultaneous access and thus ensures data consistency. For more information, refer to the `Synch Manager EtherCAT documentation `_. +Sync Manager can be configured with the following options: + +.. list-table:: + :widths: 15 35 + :header-rows: 1 + + * - Sync Manager flag + - Description + * - :code:`index` + - Sync Manager index. + * - :code:`type` + - Sync Manager type. Can be either :code:`output` or :code:`input`. + * - :code:`pdo` + - PDO to be mapped on the Sync Manager. Can be :code:`rpdo`, :code:`tpdo` or :code:`~` if empty. + * - :code:`watchdog` + - Enables Sync Manager Watchdog. Can be :code:`disable` or :code:`enable`. + +.. note:: If :code:`sm` is not specified, the default Sync Manager configuration is : + + .. code-block:: yaml + + sm: # Sync Manager + - {index: 0, type: output, pdo: ~, watchdog: disable} + - {index: 1, type: input, pdo: ~, watchdog: disable} + - {index: 2, type: output, pdo: rpdo, watchdog: enable} + - {index: 3, type: input, pdo: tpdo, watchdog: disable} + +Usage +----- + +Example configuration for the Beckhoff EL3104 analog input module: + +.. code-block:: yaml + + # Configuration file for Beckhoff EL3104 + vendor_id: 0x00000002 + product_id: 0x0c1e3052 + tpdo: # TxPDO + - index: 0x1a00 + channels: + - {index: 0x3101, sub_index: 1, type: uint8} + - {index: 0x3101, sub_index: 2, type: int16, state_interface: analog_input.1, factor: 0.000305185} + - index: 0x1a01 + channels: + - {index: 0x3102, sub_index: 1, type: uint8} + - {index: 0x3102, sub_index: 2, type: int16, state_interface: analog_input.2, factor: 0.000305185} + sm: # Sync Manager + - {index: 0, type: output, pdo: ~, watchdog: disable} + - {index: 1, type: input, pdo: ~, watchdog: disable} + - {index: 2, type: output, pdo: ~, watchdog: disable} + - {index: 3, type: input, pdo: tpdo, watchdog: disable} + +Example configuration for the Beckhoff EL2008 digital output module using data type :code:`bool` with :code:`mask`: + +.. code-block:: yaml + + # Configuration file for Beckhoff EL2008 + vendor_id: 0x00000002 + product_id: 0x07d83052 + rpdo: # RxPDO + - index: 0x1a00 + channels: + - {index: 0x6000, sub_index: 1, type: bool, mask: 1, command_interface: d_output.1} + - index: 0x1a01 + channels: + - {index: 0x6010, sub_index: 1, type: bool} + - index: 0x1a02 + channels: + - {index: 0x6020, sub_index: 1, type: bool} + - index: 0x1a03 + channels: + - {index: 0x6030, sub_index: 1, type: bool, mask: 8, command_interface: d_output.4} + - index: 0x1a04 + channels: + - {index: 0x6040, sub_index: 1, type: bool} + - index: 0x1a05 + channels: + - {index: 0x6050, sub_index: 1, type: bool} + - index: 0x1a06 + channels: + - {index: 0x6060, sub_index: 1, type: bool} + - index: 0x1a07 + channels: + - {index: 0x6070, sub_index: 1, type: bool} + sm: # Sync Manager + - {index: 0, type: output, pdo: rpdo, watchdog: enable} + +.. note:: In this configuration only digital output 1 and 4 will be used and are therefore configured. The other channels are set up with the mandatory tags :code:`index`, :code:`sub_index` and :code:`type` to fill the data layout expected by the module. + +This configuration can be used for controlling a :code:`gpio` component. Here is an example urdf for :code:`ros2_control` using this configuration together with the :code:`GenericEcSlave` plugin: + +.. code-block:: xml + + + + ethercat_driver/EthercatDriver + 0 + 100 + + + + + + + ethercat_generic_plugins/GenericEcSlave + 0 + 0 + /path/to/EL3104_slave_config.yaml + + + + + + + + ethercat_generic_plugins/GenericEcSlave + 0 + 1 + /path/to/EL2008_slave_config.yaml + + +