diff --git a/README.md b/README.md
index a53ce562..25f378e4 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,7 @@ Initially this repo supported only the 2f-85 however we want to also support the
## Build status
Currently the `main` branch is used for all current releases: Humble, Iron and Rolling.
+The `jazzy` branch adds support for ROS 2 Jazzy Jalisco (Ubuntu 24.04).
As this is not a core ROS 2 package API/ABI breakage is not guaranteed, it is done as best effort and takes into account maintenance costs.
This is not sponsored or maintained by Robotiq we try to keep everything on main to reduce maintenance overhead.
@@ -29,6 +30,11 @@ ROS2 Distro | Branch | Build status | Documentation | Released packages
:---------: | :----: | :----------: | :-----------: | :---------------:
**Iron** | [`main`](https://github.com/PickNikRobotics/ros2_robotiq_gripper/tree/main) | [](https://github.com/PickNikRobotics/ros2_robotiq_gripper/actions/workflows/iron-binary-build-main.yml?branch=main)
[](https://github.com/PickNikRobotics/ros2_robotiq_gripper/actions/workflows/iron-semi-binary-build-main.yml?branch=main) | | [ros2_robotiq_gripper](https://index.ros.org/p/ros2_robotiq_gripper/github-PickNikRobotics-ros2_robotiq_grippper/#iron)
+
+ROS2 Distro | Branch | Build status | Documentation | Released packages
+:---------: | :----: | :----------: | :-----------: | :---------------:
+**Jazzy** | [`jazzy`](#) | N/A | | Not yet released
+
### Explanation of different build types
**NOTE**: There are three build stages checking current and future compatibility of the package.
@@ -45,3 +51,62 @@ ROS2 Distro | Branch | Build status | Documentation | Released packages
Uses repos file: `$NAME$.repos`
1. Source build - also core ROS packages are build from source. It shows potential issues in the mid future.
+
+---
+
+## ROS 2 Jazzy Jalisco Support
+
+This fork adds support for **ROS 2 Jazzy Jalisco** (Ubuntu 24.04). The Jazzy branch includes API compatibility updates required for the newer ROS 2 release.
+
+### Installation (Jazzy)
+
+```bash
+# Create workspace
+mkdir -p ~/ws_robotiq/src
+cd ~/ws_robotiq/src
+
+# Clone this repository (jazzy branch)
+git clone -b jazzy https://github.com/bryceag11/ros2_robotiq_gripper.git
+
+# Import dependencies (gets the serial package)
+vcs import . < ros2_robotiq_gripper/ros2_robotiq_gripper.rolling.repos
+
+# Build
+cd ~/ws_robotiq
+colcon build --symlink-install
+
+# Source
+source install/setup.bash
+```
+
+### Changes from Humble/Iron/Rolling
+
+The Jazzy port includes the following updates for API compatibility:
+
+1. **Hardware Interface API Updates**
+ - Updated `ResourceManager` constructor to use new Jazzy signature with `rclcpp::Clock` and `rclcpp::Logger`
+ - Implemented new `on_init(const HardwareComponentInterfaceParams&)` method alongside deprecated signature
+ - Changed from `rclcpp::ClockType::SYSTEM_TIME` to `RCL_SYSTEM_TIME` constant
+
+2. **Controller Interface Updates**
+ - Updated to check return values from `LoanedCommandInterface::set_value()` (now marked with `[[nodiscard]]`)
+ - Replaced deprecated `get_value()` with `get_optional()` for safer value retrieval
+ - Added proper error handling for command interface operations
+
+3. **CMake Updates**
+ - Added CMake policy CMP0060 to suppress harmless runtime search path warnings
+ - Fixed format string warnings in logging statements
+
+4. **Dependencies**
+ - Requires the `serial` package from [tylerjw/serial](https://github.com/tylerjw/serial) (imported via `.repos` file)
+ - All other dependencies remain the same as Humble/Iron/Rolling
+
+### Tested Environment
+
+- Ubuntu 24.04 LTS (Noble Numbat)
+- ROS 2 Jazzy Jalisco
+- All packages build successfully without errors
+
+### Contributing
+
+This Jazzy port was created to enable compatibility with Ubuntu 24.04 systems. If you encounter issues or have improvements, please open an issue or pull request.
diff --git a/robotiq_controllers/CMakeLists.txt b/robotiq_controllers/CMakeLists.txt
index c4334bc5..72ea8416 100644
--- a/robotiq_controllers/CMakeLists.txt
+++ b/robotiq_controllers/CMakeLists.txt
@@ -1,6 +1,11 @@
cmake_minimum_required(VERSION 3.8)
project(robotiq_controllers)
+# Suppress CMake warning about runtime search path cycles
+if(POLICY CMP0060)
+ cmake_policy(SET CMP0060 NEW)
+endif()
+
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
diff --git a/robotiq_controllers/src/robotiq_activation_controller.cpp b/robotiq_controllers/src/robotiq_activation_controller.cpp
index aa63d214..02ebdef8 100644
--- a/robotiq_controllers/src/robotiq_activation_controller.cpp
+++ b/robotiq_controllers/src/robotiq_activation_controller.cpp
@@ -105,14 +105,33 @@ rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn Roboti
bool RobotiqActivationController::reactivateGripper(std_srvs::srv::Trigger::Request::SharedPtr /*req*/,
std_srvs::srv::Trigger::Response::SharedPtr resp)
{
- command_interfaces_[REACTIVATE_GRIPPER_RESPONSE].set_value(ASYNC_WAITING);
- command_interfaces_[REACTIVATE_GRIPPER_CMD].set_value(1.0);
+ // Set values and check for success (required due to nodiscard attribute)
+ if (!command_interfaces_[REACTIVATE_GRIPPER_RESPONSE].set_value(ASYNC_WAITING))
+ {
+ resp->success = false;
+ resp->message = "Failed to set gripper response interface";
+ return false;
+ }
+ if (!command_interfaces_[REACTIVATE_GRIPPER_CMD].set_value(1.0))
+ {
+ resp->success = false;
+ resp->message = "Failed to set gripper command interface";
+ return false;
+ }
- while (command_interfaces_[REACTIVATE_GRIPPER_RESPONSE].get_value() == ASYNC_WAITING)
+ // Use get_optional instead of deprecated get_value
+ while (true)
{
+ auto response_opt = command_interfaces_[REACTIVATE_GRIPPER_RESPONSE].get_optional();
+ if (response_opt.has_value() && response_opt.value() != ASYNC_WAITING)
+ {
+ break;
+ }
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
- resp->success = command_interfaces_[REACTIVATE_GRIPPER_RESPONSE].get_value();
+
+ auto final_response = command_interfaces_[REACTIVATE_GRIPPER_RESPONSE].get_optional();
+ resp->success = final_response.has_value() && final_response.value() > 0.0;
return resp->success;
}
diff --git a/robotiq_driver/include/robotiq_driver/hardware_interface.hpp b/robotiq_driver/include/robotiq_driver/hardware_interface.hpp
index 517249ab..0a5eadf6 100644
--- a/robotiq_driver/include/robotiq_driver/hardware_interface.hpp
+++ b/robotiq_driver/include/robotiq_driver/hardware_interface.hpp
@@ -71,7 +71,7 @@ class RobotiqGripperHardwareInterface : public hardware_interface::SystemInterfa
/**
* Initialization of the hardware interface from data parsed from the
- * robot's URDF.
+ * robot's URDF (deprecated signature for backward compatibility).
* @param hardware_info Structure with data from URDF.
* @returns CallbackReturn::SUCCESS if required data are provided and can be
* parsed or CallbackReturn::ERROR if any error happens or data are missing.
@@ -79,6 +79,16 @@ class RobotiqGripperHardwareInterface : public hardware_interface::SystemInterfa
ROBOTIQ_DRIVER_PUBLIC
CallbackReturn on_init(const hardware_interface::HardwareInfo& info) override;
+ /**
+ * Initialization of the hardware interface from data parsed from the
+ * robot's URDF (new Jazzy signature).
+ * @param params Parameters including hardware_info and executor.
+ * @returns CallbackReturn::SUCCESS if required data are provided and can be
+ * parsed or CallbackReturn::ERROR if any error happens or data are missing.
+ */
+ ROBOTIQ_DRIVER_PUBLIC
+ CallbackReturn on_init(const hardware_interface::HardwareComponentInterfaceParams& params) override;
+
/**
* Connect to the hardware.
* @param previous_state The previous state.
diff --git a/robotiq_driver/package.xml b/robotiq_driver/package.xml
index 856ed977..e3d35078 100644
--- a/robotiq_driver/package.xml
+++ b/robotiq_driver/package.xml
@@ -33,6 +33,8 @@
ament_cmake_gmock
+
+ ros2_control_test_assets
ament_cmake
diff --git a/robotiq_driver/src/hardware_interface.cpp b/robotiq_driver/src/hardware_interface.cpp
index b837af51..46ec298a 100644
--- a/robotiq_driver/src/hardware_interface.cpp
+++ b/robotiq_driver/src/hardware_interface.cpp
@@ -37,6 +37,7 @@
#include
#include
+#include
#include
@@ -73,10 +74,19 @@ RobotiqGripperHardwareInterface::RobotiqGripperHardwareInterface(std::unique_ptr
}
hardware_interface::CallbackReturn RobotiqGripperHardwareInterface::on_init(const hardware_interface::HardwareInfo& info)
+{
+ // Call the new on_init with params struct for backward compatibility
+ hardware_interface::HardwareComponentInterfaceParams params;
+ params.hardware_info = info;
+ return on_init(params);
+}
+
+hardware_interface::CallbackReturn RobotiqGripperHardwareInterface::on_init(
+ const hardware_interface::HardwareComponentInterfaceParams& params)
{
RCLCPP_DEBUG(kLogger, "on_init");
- if (hardware_interface::SystemInterface::on_init(info) != CallbackReturn::SUCCESS)
+ if (hardware_interface::SystemInterface::on_init(params.hardware_info) != CallbackReturn::SUCCESS)
{
return CallbackReturn::ERROR;
}
@@ -107,8 +117,8 @@ hardware_interface::CallbackReturn RobotiqGripperHardwareInterface::on_init(cons
if (joint.command_interfaces[0].name != hardware_interface::HW_IF_POSITION)
{
- RCLCPP_FATAL(kLogger, "Joint '%s' has %s command interfaces found. '%s' expected.", joint.name.c_str(),
- joint.command_interfaces[0].name.c_str(), hardware_interface::HW_IF_POSITION);
+ RCLCPP_FATAL(kLogger, "Joint '%s' does not have expected '%s' interface.", joint.name.c_str(),
+ hardware_interface::HW_IF_POSITION);
return CallbackReturn::ERROR;
}
@@ -156,11 +166,50 @@ RobotiqGripperHardwareInterface::on_configure(const rclcpp_lifecycle::State& pre
return CallbackReturn::ERROR;
}
- // Open the serial port and handshake.
- bool connected = driver_->connect();
+ // Open the serial port and handshake with retry logic
+ // This allows time for tool communication (socat) to create virtual serial port
+ const int max_retries = 10;
+ const auto retry_delay = std::chrono::milliseconds(500);
+ bool connected = false;
+
+ for (int attempt = 1; attempt <= max_retries && !connected; ++attempt)
+ {
+ try
+ {
+ RCLCPP_INFO(kLogger, "Attempting to connect to Robotiq gripper (attempt %d/%d)...", attempt, max_retries);
+ connected = driver_->connect();
+
+ if (!connected)
+ {
+ if (attempt < max_retries)
+ {
+ RCLCPP_WARN(kLogger, "Connection failed, retrying in %ld ms...", retry_delay.count());
+ std::this_thread::sleep_for(retry_delay);
+ }
+ }
+ else
+ {
+ RCLCPP_INFO(kLogger, "Successfully connected to Robotiq gripper");
+ }
+ }
+ catch (const std::exception& e)
+ {
+ if (attempt < max_retries)
+ {
+ RCLCPP_WARN(kLogger, "Connection attempt %d failed: %s. Retrying in %ld ms...",
+ attempt, e.what(), retry_delay.count());
+ std::this_thread::sleep_for(retry_delay);
+ }
+ else
+ {
+ throw; // Re-throw on last attempt
+ }
+ }
+ }
+
if (!connected)
{
- RCLCPP_ERROR(kLogger, "Cannot connect to the Robotiq gripper");
+ RCLCPP_ERROR(kLogger, "Cannot connect to the Robotiq gripper after %d attempts", max_retries);
return CallbackReturn::ERROR;
}
}
diff --git a/robotiq_driver/tests/CMakeLists.txt b/robotiq_driver/tests/CMakeLists.txt
index 5db0b3c8..357e1d89 100644
--- a/robotiq_driver/tests/CMakeLists.txt
+++ b/robotiq_driver/tests/CMakeLists.txt
@@ -2,6 +2,7 @@
find_package(ament_cmake_gtest REQUIRED)
find_package(ament_cmake_gmock REQUIRED)
find_package(ament_lint_auto REQUIRED)
+find_package(ros2_control_test_assets REQUIRED)
ament_lint_auto_find_test_dependencies()
@@ -20,7 +21,9 @@ target_include_directories(test_robotiq_gripper_hardware_interface
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
)
target_link_libraries(test_robotiq_gripper_hardware_interface robotiq_driver)
-ament_target_dependencies(test_robotiq_gripper_hardware_interface)
+ament_target_dependencies(test_robotiq_gripper_hardware_interface
+ ros2_control_test_assets
+)
###############################################################################
# test_default_serial_factory
diff --git a/robotiq_driver/tests/test_robotiq_gripper_hardware_interface.cpp b/robotiq_driver/tests/test_robotiq_gripper_hardware_interface.cpp
index ea700834..046e7082 100644
--- a/robotiq_driver/tests/test_robotiq_gripper_hardware_interface.cpp
+++ b/robotiq_driver/tests/test_robotiq_gripper_hardware_interface.cpp
@@ -29,13 +29,14 @@
#include
#include
-#if __has_include()
-#include
-#else
-#include
-#endif
+#include
-#include
+#include
+#include
+#include
+
+#include
+#include
namespace robotiq_driver::test
{
@@ -46,46 +47,30 @@ namespace robotiq_driver::test
*/
TEST(TestRobotiqGripperHardwareInterface, load_urdf)
{
- std::string urdf =
+ std::string urdf_control_ =
R"(
-
-
-
-
-
-
-
-
-
-
-
-
-
- robotiq_driver/RobotiqGripperHardwareInterface
- 1.0
- 0.5
- /dev/ttyUSB0
- 0.7929
-
-
-
-
- 0.7929
-
-
-
-
-
- )";
-
- rclcpp::Node node{ "test_robotiq_gripper_hardware_interface" };
+
+
+ robotiq_driver/RobotiqGripperHardwareInterface
+ 1.0
+ 0.5
+ /dev/ttyUSB0
+ 0.7929
+
+
+
+
+ 0.7929
+
+
+
+
+ )";
-#if HARDWARE_INTERFACE_VERSION_GTE(4, 13, 0)
- // Initialize the resource manager
- hardware_interface::ResourceManager rm(urdf, node.get_node_clock_interface(), node.get_node_logging_interface());
-#else
- hardware_interface::ResourceManager rm(urdf);
-#endif
+ auto urdf = ros2_control_test_assets::urdf_head + urdf_control_ + ros2_control_test_assets::urdf_tail;
+ auto clock = std::make_shared(RCL_SYSTEM_TIME);
+ auto logger = rclcpp::get_logger("test_robotiq_gripper_hardware_interface");
+ hardware_interface::ResourceManager rm(urdf, clock, logger);
// Check interfaces
EXPECT_EQ(1u, rm.system_components_size());
diff --git a/robotiq_hardware_tests/CMakeLists.txt b/robotiq_hardware_tests/CMakeLists.txt
index 668cf319..ad137152 100644
--- a/robotiq_hardware_tests/CMakeLists.txt
+++ b/robotiq_hardware_tests/CMakeLists.txt
@@ -3,6 +3,11 @@
cmake_minimum_required(VERSION 3.8)
project(robotiq_hardware_tests LANGUAGES CXX)
+# Suppress CMake warning about runtime search path cycles
+if(POLICY CMP0060)
+ cmake_policy(SET CMP0060 NEW)
+endif()
+
# This module provides installation directories as per the GNU coding standards.
include(GNUInstallDirs)