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
65 changes: 65 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -29,6 +30,11 @@ ROS2 Distro | Branch | Build status | Documentation | Released packages
:---------: | :----: | :----------: | :-----------: | :---------------:
**Iron** | [`main`](https://github.com/PickNikRobotics/ros2_robotiq_gripper/tree/main) | [![Iron Binary Build](https://github.com/PickNikRobotics/ros2_robotiq_gripper/actions/workflows/iron-binary-build-main.yml/badge.svg?branch=main)](https://github.com/PickNikRobotics/ros2_robotiq_gripper/actions/workflows/iron-binary-build-main.yml?branch=main) <br /> [![Iron Semi-Binary Build](https://github.com/PickNikRobotics/ros2_robotiq_gripper/actions/workflows/iron-semi-binary-build-main.yml/badge.svg?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.
Expand All @@ -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<double>()` 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.
5 changes: 5 additions & 0 deletions robotiq_controllers/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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()
Expand Down
27 changes: 23 additions & 4 deletions robotiq_controllers/src/robotiq_activation_controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<double>();
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<double>();
resp->success = final_response.has_value() && final_response.value() > 0.0;

return resp->success;
}
Expand Down
12 changes: 11 additions & 1 deletion robotiq_driver/include/robotiq_driver/hardware_interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,24 @@ 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.
*/
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.
Expand Down
2 changes: 2 additions & 0 deletions robotiq_driver/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@

<!-- Support for gtest and gmock-based tests in the ament buildsystem in CMake. -->
<test_depend>ament_cmake_gmock</test_depend>
<!-- Test utilities for ros2_control -->
<test_depend>ros2_control_test_assets</test_depend>

<export>
<build_type>ament_cmake</build_type>
Expand Down
61 changes: 55 additions & 6 deletions robotiq_driver/src/hardware_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

#include <hardware_interface/actuator_interface.hpp>
#include <hardware_interface/types/hardware_interface_type_values.hpp>
#include <hardware_interface/types/hardware_component_interface_params.hpp>

#include <rclcpp/rclcpp.hpp>

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
}
Expand Down
5 changes: 4 additions & 1 deletion robotiq_driver/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand All @@ -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
Expand Down
73 changes: 29 additions & 44 deletions robotiq_driver/tests/test_robotiq_gripper_hardware_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,14 @@
#include <gtest/gtest.h>

#include <hardware_interface/resource_manager.hpp>
#if __has_include(<hardware_interface/hardware_interface/version.h>)
#include <hardware_interface/hardware_interface/version.h>
#else
#include <hardware_interface/version.h>
#endif
#include <hardware_interface/types/lifecycle_state_names.hpp>

#include <rclcpp/node.hpp>
#include <lifecycle_msgs/msg/state.hpp>
#include <rclcpp/rclcpp.hpp>
#include <rclcpp_lifecycle/state.hpp>

#include <ros2_control_test_assets/components_urdfs.hpp>
#include <ros2_control_test_assets/descriptions.hpp>

namespace robotiq_driver::test
{
Expand All @@ -46,46 +47,30 @@ namespace robotiq_driver::test
*/
TEST(TestRobotiqGripperHardwareInterface, load_urdf)
{
std::string urdf =
std::string urdf_control_ =
R"(
<?xml version="1.0" encoding="utf-8"?>
<robot name="test_robot">
<link name="robotiq_85_base_link"/>
<link name="robotiq_85_left_knuckle_link"/>
<joint name="robotiq_85_left_knuckle_joint" type="revolute">
<parent link="robotiq_85_base_link" />
<child link="robotiq_85_left_knuckle_link" />
<axis xyz="0 -1 0" />
<origin xyz="0.03060114 0.0 0.05490452" rpy="0 0 0" />
<limit lower="0.0" upper="0.8" velocity="0.5" effort="50" />
</joint>
<ros2_control name="robotiq_driver_ros2_control" type="system">
<hardware>
<plugin>robotiq_driver/RobotiqGripperHardwareInterface</plugin>
<param name="gripper_speed_multiplier">1.0</param>
<param name="gripper_force_multiplier">0.5</param>
<param name="COM_port">/dev/ttyUSB0</param>
<param name="gripper_closed_position">0.7929</param>
</hardware>
<joint name="robotiq_85_left_knuckle_joint">
<command_interface name="position" />
<state_interface name="position">
<param name="initial_value">0.7929</param>
</state_interface>
<state_interface name="velocity"/>
</joint>
</ros2_control>
</robot>
)";

rclcpp::Node node{ "test_robotiq_gripper_hardware_interface" };
<ros2_control name="robotiq_driver_ros2_control" type="system">
<hardware>
<plugin>robotiq_driver/RobotiqGripperHardwareInterface</plugin>
<param name="gripper_speed_multiplier">1.0</param>
<param name="gripper_force_multiplier">0.5</param>
<param name="COM_port">/dev/ttyUSB0</param>
<param name="gripper_closed_position">0.7929</param>
</hardware>
<joint name="robotiq_85_left_knuckle_joint">
<command_interface name="position" />
<state_interface name="position">
<param name="initial_value">0.7929</param>
</state_interface>
<state_interface name="velocity"/>
</joint>
</ros2_control>
)";

#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<rclcpp::Clock>(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());
Expand Down
5 changes: 5 additions & 0 deletions robotiq_hardware_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down