Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ jobs:
options: -v ${{github.workspace}}/:/ros/
run: |
cd /ros
# Install click, try via apt first, fallback to pip with --break-system-packages
apt-get update
apt-get install -y python3-click || (apt-get install -y python3-pip && python3 -m pip install --break-system-packages click)
# Install both system and ROS2 yaml-cpp packages
apt-get install -y libyaml-cpp-dev ros-jazzy-yaml-cpp-vendor pkg-config
. /opt/ros/jazzy/setup.sh
rosdep install --ignore-src --from-paths . -y -r && \
colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release
Expand All @@ -47,6 +52,11 @@ jobs:
options: -v ${{github.workspace}}/:/ros/
run: |
cd /ros
# Install click, try via apt first, fallback to pip with --break-system-packages
apt-get update
apt-get install -y python3-click || (apt-get install -y python3-pip && python3 -m pip install --break-system-packages click)
# Install both system and ROS2 yaml-cpp packages
apt-get install -y libyaml-cpp-dev ros-jazzy-yaml-cpp-vendor pkg-config
. /opt/ros/jazzy/setup.sh
rosdep install --ignore-src --from-paths . -y -r && \
colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release
Expand Down
18 changes: 9 additions & 9 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
repos:
# Standard hooks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v6.0.0
hooks:
- id: check-added-large-files
- id: check-ast
Expand All @@ -35,7 +35,7 @@ repos:

# Python hooks
- repo: https://github.com/asottile/pyupgrade
rev: v3.3.1
rev: v3.20.0
hooks:
- id: pyupgrade
args: [--py36-plus]
Expand All @@ -48,7 +48,7 @@ repos:
args: ["--ignore=D100,D101,D102,D103,D104,D105,D106,D107,D203,D212,D404"]

- repo: https://github.com/pycqa/flake8
rev: 6.0.0
rev: 7.3.0
hooks:
- id: flake8
args: ["--extend-ignore=E501"]
Expand All @@ -59,7 +59,7 @@ repos:
- id: ament_uncrustify
name: ament_uncrustify
description: Uncrustify.
stages: [commit]
stages: [pre-commit]
entry: ament_uncrustify
language: system
files: \.(h\+\+|h|hh|hxx|hpp|cuh|c|cc|cpp|cu|c\+\+|cxx|tpp|txx)$
Expand Down Expand Up @@ -92,7 +92,7 @@ repos:
- id: ament_cpplint
name: ament_cpplint
description: Static code analysis of C/C++ files.
stages: [commit]
stages: [pre-commit]
entry: ament_cpplint
language: system
files: \.(h\+\+|h|hh|hxx|hpp|cuh|c|cc|cpp|cu|c\+\+|cxx|tpp|txx)$
Expand All @@ -104,7 +104,7 @@ repos:
- id: ament_lint_cmake
name: ament_lint_cmake
description: Check format of CMakeLists.txt files.
stages: [commit]
stages: [pre-commit]
entry: ament_lint_cmake
language: system
files: CMakeLists\.txt$
Expand All @@ -115,13 +115,13 @@ repos:
- id: ament_copyright
name: ament_copyright
description: Check if copyright notice is available in all files.
stages: [commit]
stages: [pre-commit]
entry: ament_copyright
language: system

# Docs - RestructuredText hooks
- repo: https://github.com/PyCQA/doc8
rev: v1.1.1
rev: v2.0.0
hooks:
- id: doc8
args: ['--max-line-length=100', '--ignore=D001']
Expand All @@ -138,7 +138,7 @@ repos:
# Spellcheck in comments and docs
# skipping of *.svg files is not working...
- repo: https://github.com/codespell-project/codespell
rev: v2.2.2
rev: v2.4.1
hooks:
- id: codespell
args: ['--write-changes']
Expand Down
116 changes: 107 additions & 9 deletions ethercat_driver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,28 @@ endif()

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(ament_cmake_ros REQUIRED)

find_package(hardware_interface REQUIRED)
find_package(pluginlib REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclcpp_lifecycle REQUIRED)
find_package(ethercat_interface REQUIRED)
find_package(yaml_cpp_vendor REQUIRED)

add_library(
${PROJECT_NAME}
SHARED
src/ethercat_driver.cpp)
# Find system yaml-cpp for proper linking
find_package(PkgConfig REQUIRED)
pkg_check_modules(YAML_CPP REQUIRED yaml-cpp)

target_include_directories(
${PROJECT_NAME}
PRIVATE
include
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
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)

ament_target_dependencies(
Expand All @@ -31,27 +38,117 @@ ament_target_dependencies(
rclcpp
rclcpp_lifecycle
ethercat_interface
yaml_cpp_vendor
)

# Explicitly link yaml-cpp
target_link_libraries(${PROJECT_NAME} ${YAML_CPP_LIBRARIES})
target_include_directories(${PROJECT_NAME} PRIVATE ${YAML_CPP_INCLUDE_DIRS})
target_compile_options(${PROJECT_NAME} PRIVATE ${YAML_CPP_CFLAGS_OTHER})

# Causes the visibility macros to use dllexport rather than dllimport,
# which is appropriate when building the dll but not consuming it.
target_compile_definitions(ethercat_driver PRIVATE "ETHERCAT_DRIVER_BUILDING_LIBRARY")
target_compile_definitions(${PROJECT_NAME} PRIVATE "ETHERCAT_DRIVER_BUILDING_LIBRARY")

# prevent pluginlib from using boost
target_compile_definitions(${PROJECT_NAME} PUBLIC "PLUGINLIB__DISABLE_BOOST_FUNCTIONS")

pluginlib_export_plugin_description_file(hardware_interface ethercat_driver_plugin.xml)

# INSTALL
install(
TARGETS ${PROJECT_NAME}
DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
)
install(
DIRECTORY include/
DESTINATION include
)

if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
find_package(ament_cmake_gtest REQUIRED)
find_package(ethercat_interface REQUIRED)
ament_lint_auto_find_test_dependencies()

# Ensure test data is copied to the build directory
set(CFG_FILES
safety.ros2_control.xacro
safety_estop.ros2_control.template.xacro
estop_ethercat_safety.yaml
test_config_ethercat_safety.yaml
beckhoff_ek1914.yaml
beckhoff_el1918.yaml
)

set(CFG_IN ${CMAKE_CURRENT_SOURCE_DIR}/examples/configurations)
set(CFG_DST ${CMAKE_CURRENT_BINARY_DIR}/test_configurations)
list(TRANSFORM CFG_FILES PREPEND "${CFG_IN}" OUTPUT_VARIABLE CFG_SRC)

# Ensure the destination directory exists
file(MAKE_DIRECTORY ${CFG_DST})

# List to keep track of the output files
set(CFG_OUT)

foreach(file ${CFG_FILES})
set(src_file "${CMAKE_CURRENT_SOURCE_DIR}/examples/configurations/${file}")
set(dst_file "${CFG_DST}/${file}")

add_custom_command(
OUTPUT ${dst_file}
COMMAND ${CMAKE_COMMAND} -E copy ${src_file} ${dst_file}
DEPENDS ${src_file}
COMMENT "Copying ${src_file} to ${dst_file}"
)

list(APPEND CFG_OUT ${dst_file})
endforeach()
# message(WARNING "Copying ${CFG_SRC} to ${CFG_DST}")

# Create a custom target to group the copy commands
add_custom_target(copy_safety_config ALL DEPENDS ${CFG_OUT})

set(UP_PY ${CMAKE_CURRENT_SOURCE_DIR}/examples/configurations/update_slave_config_path.py)
set(UP_IN ${CFG_DST}/safety_estop.ros2_control.template.xacro)
set(UP_OUT ${CFG_DST}/safety_estop.ros2_control.xacro)
set(UP_DEPS ${UP_PY} ${UP_IN})

# message(WARNING "Running ${UP_PY} ${UP_IN} -p ${CFG_DST} -o ${UP_OUT}")
add_custom_command(
OUTPUT ${UP_OUT}
COMMAND ${CMAKE_COMMAND} -E echo "Running update_slave_config_path.py"
COMMAND ${CMAKE_COMMAND} -E env python3 ${UP_PY} ${UP_IN} -p ${CFG_DST} -o ${UP_OUT}
DEPENDS ${UP_DEPS}
COMMENT "Running update_slave_config_path.py"
)

add_custom_target(update_slave_config_path ALL DEPENDS ${UP_OUT})

ament_add_gmock(test_ethercat_safety_driver test/test_ethercat_safety_driver.cpp)
target_include_directories(test_ethercat_safety_driver PRIVATE include)

target_compile_definitions(test_ethercat_safety_driver PRIVATE "TEST_RESOURCES_DIRECTORY=\"${CFG_DST}\"")

target_link_libraries(test_ethercat_safety_driver
${PROJECT_NAME}
${YAML_CPP_LIBRARIES}
)

ament_target_dependencies(test_ethercat_safety_driver
hardware_interface
pluginlib
rclcpp
rclcpp_lifecycle
ethercat_interface
yaml_cpp_vendor
)

# Add yaml-cpp to test target as well
target_include_directories(test_ethercat_safety_driver PRIVATE ${YAML_CPP_INCLUDE_DIRS})
target_compile_options(test_ethercat_safety_driver PRIVATE ${YAML_CPP_CFLAGS_OTHER})
endif()

## EXPORTS
Expand All @@ -67,5 +164,6 @@ ament_export_dependencies(
rclcpp
rclcpp_lifecycle
ethercat_interface
yaml_cpp_vendor
)
ament_package()
9 changes: 6 additions & 3 deletions ethercat_driver/ethercat_driver_plugin.xml
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
<library path="ethercat_driver">
<class name="ethercat_driver/EthercatDriver"
type="ethercat_driver::EthercatDriver"
base_class_type="hardware_interface::SystemInterface">
<class name="ethercat_driver/EthercatDriver" type="ethercat_driver::EthercatDriver" base_class_type="hardware_interface::SystemInterface">
<description>
EtherCAT Driver for ros2_control.
</description>
</class>
<class name="ethercat_driver/EthercatSafetyDriver" type="ethercat_driver::EthercatSafetyDriver" base_class_type="hardware_interface::SystemInterface">
<description>
EtherCAT Safety Driver for ros2_control.
</description>
</class>
</library>
93 changes: 93 additions & 0 deletions ethercat_driver/examples/configurations/beckhoff_ek1914.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Configuration file for Beckhoff EK1914
# Description : Coupler, 4-channel digital input,
# 2-channel digital safety input, 4-channel digital output,
# 2-channel digital safety output, 24 V DC, 1 ms (TBC).
vendor_id: 0x00000002
product_id: 0x077a2c52
tpdo: # Slave-OUT & Master-IN
- index: 0x1a00
channels:
- { index: 0x6000, sub_index: 0x01, type: int8 }
- { index: 0x6001, sub_index: 0x01, type: bool, mask: 1 }
- { index: 0x6001, sub_index: 0x02, type: bool, mask: 2 }
- { index: 0x0000, sub_index: 0x00, type: bit6 }
- { index: 0x6000, sub_index: 0x03, type: int16 }
- { index: 0x6000, sub_index: 0x02, type: int16 }
- index: 0x1a01
channels:
- {
index: 0x6010,
sub_index: 0x01,
type: bool,
mask: 1,
state_interface: input_1,
}
- {
index: 0x6010,
sub_index: 0x02,
type: bool,
mask: 2,
state_interface: input_2,
}
- {
index: 0x6010,
sub_index: 0x03,
type: bool,
mask: 4,
state_interface: input_3,
}
- {
index: 0x6010,
sub_index: 0x04,
type: bool,
mask: 8,
state_interface: input_4,
}
- { index: 0x0000, sub_index: 0x00, type: bit12 }
rpdo: # Slave-IN & Master-OUT
- index: 0x1600
channels:
- { index: 0x7000, sub_index: 0x01, type: int8 }
- { index: 0x7001, sub_index: 0x01, type: bool, mask: 1 }
- { index: 0x7001, sub_index: 0x02, type: bool, mask: 2 }
- { index: 0x0000, sub_index: 0x00, type: bit6 }
- { index: 0x7000, sub_index: 0x03, type: int16 }
- { index: 0x7000, sub_index: 0x02, type: int16 }
- index: 0x1601
channels:
- {
index: 0x7010,
sub_index: 0x01,
type: bool,
mask: 1,
command_interface: output_1,
}
- {
index: 0x7010,
sub_index: 0x02,
type: bool,
mask: 2,
command_interface: output_2,
}
- {
index: 0x7010,
sub_index: 0x03,
type: bool,
mask: 4,
command_interface: output_3,
}
- {
index: 0x7010,
sub_index: 0x04,
type: bool,
mask: 8,
command_interface: output_4,
}
- { index: 0x7010, sub_index: 0x05, type: bool, mask: 16 }
- { index: 0x7010, sub_index: 0x06, type: bool, mask: 32 }
- { index: 0x0000, sub_index: 0x00, type: bit10 }
sm:
- { index: 0, type: output, watchdog: disable }
- { index: 1, type: input, watchdog: disable }
- { index: 2, type: output, pdo: rpdo, watchdog: disable }
- { index: 3, type: input, pdo: tpdo, watchdog: disable }
Loading