Skip to content

Commit 3d03572

Browse files
authored
Add utility node to transform wrench messages for a list of frames (#2021)
1 parent ec198b1 commit 3d03572

File tree

10 files changed

+1124
-0
lines changed

10 files changed

+1124
-0
lines changed

doc/release_notes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@ Release Notes: Kilted Kaiju to Lyrical Luth
44
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
55

66
This list summarizes important changes between Kilted Kaiju (previous) and Lyrical Luth (current) releases.
7+
8+
force_torque_sensor_broadcaster
9+
*******************************
10+
* Added support for transforming Wrench messages to a given list of target frames. This is useful when applications need force/torque data in their preferred coordinate frames. (`#2021 <https://github.com/ros-controls/ros2_controllers/pull/2021/files>`__).

force_torque_sensor_broadcaster/CMakeLists.txt

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ set(THIS_PACKAGE_INCLUDE_DEPENDS
1515
rclcpp
1616
rclcpp_lifecycle
1717
realtime_tools
18+
tf2
19+
tf2_ros
20+
tf2_geometry_msgs
1821
)
1922

2023
find_package(ament_cmake REQUIRED)
@@ -27,6 +30,10 @@ generate_parameter_library(force_torque_sensor_broadcaster_parameters
2730
src/force_torque_sensor_broadcaster_parameters.yaml
2831
)
2932

33+
generate_parameter_library(wrench_transformer_parameters
34+
src/wrench_transformer_parameters.yaml
35+
)
36+
3037
add_library(force_torque_sensor_broadcaster SHARED
3138
src/force_torque_sensor_broadcaster.cpp
3239
)
@@ -49,6 +56,37 @@ target_link_libraries(force_torque_sensor_broadcaster PUBLIC
4956
pluginlib_export_plugin_description_file(
5057
controller_interface force_torque_sensor_broadcaster.xml)
5158

59+
# Wrench transformer library
60+
add_library(wrench_transformer SHARED
61+
src/wrench_transformer.cpp
62+
)
63+
target_compile_features(wrench_transformer PUBLIC cxx_std_17)
64+
target_include_directories(wrench_transformer PUBLIC
65+
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
66+
$<INSTALL_INTERFACE:include/force_torque_sensor_broadcaster>
67+
)
68+
target_link_libraries(wrench_transformer PUBLIC
69+
wrench_transformer_parameters
70+
rclcpp::rclcpp
71+
tf2::tf2
72+
tf2_ros::tf2_ros
73+
tf2_geometry_msgs::tf2_geometry_msgs
74+
${geometry_msgs_TARGETS}
75+
)
76+
77+
# Wrench transformer executable
78+
add_executable(wrench_transformer_node
79+
src/wrench_transformer_main.cpp
80+
)
81+
target_compile_features(wrench_transformer_node PUBLIC cxx_std_17)
82+
target_include_directories(wrench_transformer_node PUBLIC
83+
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
84+
$<INSTALL_INTERFACE:include/force_torque_sensor_broadcaster>
85+
)
86+
target_link_libraries(wrench_transformer_node PUBLIC
87+
wrench_transformer
88+
)
89+
5290
if(BUILD_TESTING)
5391
find_package(ament_cmake_gmock REQUIRED)
5492
find_package(controller_manager REQUIRED)
@@ -73,6 +111,16 @@ if(BUILD_TESTING)
73111
force_torque_sensor_broadcaster
74112
)
75113

114+
ament_add_gmock(test_wrench_transformer test/test_wrench_transformer.cpp)
115+
target_compile_features(test_wrench_transformer PUBLIC cxx_std_17)
116+
target_include_directories(test_wrench_transformer PRIVATE include)
117+
target_compile_definitions(test_wrench_transformer PRIVATE
118+
TEST_FILES_DIRECTORY="${CMAKE_CURRENT_SOURCE_DIR}/test")
119+
target_link_libraries(test_wrench_transformer
120+
wrench_transformer
121+
tf2_ros::tf2_ros
122+
)
123+
76124
add_library(dummy_filter SHARED
77125
test/dummy_filter.cpp
78126
)
@@ -107,12 +155,22 @@ install(
107155
TARGETS
108156
force_torque_sensor_broadcaster
109157
force_torque_sensor_broadcaster_parameters
158+
wrench_transformer
159+
wrench_transformer_parameters
110160
EXPORT export_force_torque_sensor_broadcaster
111161
RUNTIME DESTINATION bin
112162
ARCHIVE DESTINATION lib
113163
LIBRARY DESTINATION lib
114164
)
115165

166+
# Install executable to lib/<package_name> for launch files to find it
167+
install(
168+
TARGETS
169+
wrench_transformer_node
170+
EXPORT export_force_torque_sensor_broadcaster
171+
RUNTIME DESTINATION lib/force_torque_sensor_broadcaster
172+
)
173+
116174
ament_export_targets(export_force_torque_sensor_broadcaster HAS_LIBRARY_TARGET)
117175
ament_export_dependencies(${THIS_PACKAGE_INCLUDE_DEPENDS})
118176
ament_package()

force_torque_sensor_broadcaster/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,9 @@ Controller to publish state of force-torque sensors.
66
Pluginlib-Library: force_torque_sensor_broadcaster
77

88
Plugin: force_torque_sensor_broadcaster/ForceTorqueSensorBroadcaster (controller_interface::ControllerInterface)
9+
10+
Wrench Transformer Node
11+
-----------------------
12+
The package also provides a standalone ROS 2 node ``wrench_transformer_node`` that transforms wrench messages from the force_torque_sensor_broadcaster to different target frames using TF2. This allows applications to receive force/torque data in their preferred coordinate frames.
13+
14+
See the user documentation for details on configuration and usage.

force_torque_sensor_broadcaster/doc/userdoc.rst

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,39 @@ An example parameter file for this controller can be found in `the test director
3535

3636
.. literalinclude:: ../test/force_torque_sensor_broadcaster_params.yaml
3737
:language: yaml
38+
39+
Wrench Transformer Node
40+
-----------------------
41+
The package provides a standalone ROS 2 node ``wrench_transformer_node`` that transforms wrench messages published by the ``ForceTorqueSensorBroadcaster`` controller to different target frames using TF2. This is useful when applications need force/torque data in coordinate frames other than the sensor frame.
42+
43+
The node subscribes to wrench messages from the broadcaster (either raw or filtered) and publishes transformed versions to separate topics for each target frame.
44+
45+
Usage
46+
^^^^^
47+
The wrench transformer node can be launched as a standalone executable:
48+
49+
.. code-block:: bash
50+
51+
ros2 run force_torque_sensor_broadcaster wrench_transformer_node
52+
53+
Wrench Transformer Parameters
54+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
55+
The wrench transformer uses the `generate_parameter_library <https://github.com/PickNikRobotics/generate_parameter_library>`_ to handle its parameters. The parameter `definition file for the wrench transformer <https://github.com/ros-controls/ros2_controllers/blob/{REPOS_FILE_BRANCH}/force_torque_sensor_broadcaster/src/wrench_transformer_parameters.yaml>`_ contains descriptions for all the parameters.
56+
57+
Full list of parameters:
58+
59+
.. generate_parameter_library_details:: ../src/wrench_transformer_parameters.yaml
60+
61+
Topics
62+
^^^^^^
63+
The node subscribes to:
64+
65+
- ``~/wrench`` (raw wrench messages). To subscribe to filtered wrench messages, use topic remapping: ``ros2 run ... --ros-args -r ~/wrench:=<namespace>/wrench_filtered``
66+
67+
The node publishes:
68+
69+
- ``<namespace>/<target_frame>/wrench`` for each target frame specified in ``target_frames``
70+
71+
- If the node is in the root namespace (``/``), the namespace defaults to the node name (e.g., ``/fts_wrench_transformer/<target_frame>/wrench``)
72+
- If the input topic is remapped to a filtered topic (contains "filtered" in the name), the output topics automatically append ``_filtered`` suffix (e.g., ``<namespace>/<target_frame>/wrench_filtered``)
73+
- This allows users to distinguish between transformed raw wrench data and transformed filtered wrench data
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright (c) 2025, ros2_control development team
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
/*
16+
* Authors: Julia Jia
17+
*/
18+
19+
#ifndef FORCE_TORQUE_SENSOR_BROADCASTER__WRENCH_TRANSFORMER_HPP_
20+
#define FORCE_TORQUE_SENSOR_BROADCASTER__WRENCH_TRANSFORMER_HPP_
21+
22+
#include <memory>
23+
#include <string>
24+
#include <unordered_map>
25+
#include <vector>
26+
27+
#include "geometry_msgs/msg/wrench_stamped.hpp"
28+
#include "rclcpp/rclcpp.hpp"
29+
#include "tf2_geometry_msgs/tf2_geometry_msgs.hpp"
30+
#include "tf2_ros/buffer.hpp"
31+
#include "tf2_ros/transform_listener.hpp"
32+
33+
// auto-generated by generate_parameter_library
34+
#include "force_torque_sensor_broadcaster/wrench_transformer_parameters.hpp"
35+
36+
namespace force_torque_sensor_broadcaster
37+
{
38+
39+
class WrenchTransformer : public rclcpp::Node
40+
{
41+
public:
42+
explicit WrenchTransformer(const rclcpp::NodeOptions & options = rclcpp::NodeOptions());
43+
44+
void init();
45+
46+
~WrenchTransformer() = default;
47+
48+
private:
49+
void wrench_callback(const geometry_msgs::msg::WrenchStamped::SharedPtr msg);
50+
bool transform_wrench(
51+
const geometry_msgs::msg::WrenchStamped & input_wrench, const std::string & target_frame,
52+
geometry_msgs::msg::WrenchStamped & output_wrench);
53+
54+
void setup_subscriber();
55+
void setup_publishers();
56+
57+
/**
58+
* Normalize namespace for topic construction.
59+
* If namespace is empty or root ("/"), returns node name with leading "/".
60+
* Otherwise, normalizes namespace to start with "/" and not end with "/".
61+
* @return Normalized namespace string
62+
*/
63+
std::string normalize_namespace_for_topics() const;
64+
65+
std::shared_ptr<force_torque_wrench_transformer::ParamListener> param_listener_;
66+
force_torque_wrench_transformer::Params params_;
67+
68+
rclcpp::Subscription<geometry_msgs::msg::WrenchStamped>::SharedPtr wrench_subscriber_;
69+
std::unordered_map<std::string, rclcpp::Publisher<geometry_msgs::msg::WrenchStamped>::SharedPtr>
70+
transformed_wrench_publishers_;
71+
72+
std::shared_ptr<tf2_ros::Buffer> tf_buffer_;
73+
std::shared_ptr<tf2_ros::TransformListener> tf_listener_;
74+
75+
std::string input_topic_;
76+
std::string output_topic_suffix_; // e.g., "" or "_filtered" based on input topic
77+
std::vector<std::string> target_frames_;
78+
};
79+
80+
// Function to run wrench transformer (extracted from main for testability)
81+
int run_wrench_transformer(int argc, char ** argv);
82+
83+
} // namespace force_torque_sensor_broadcaster
84+
85+
#endif // FORCE_TORQUE_SENSOR_BROADCASTER__WRENCH_TRANSFORMER_HPP_

force_torque_sensor_broadcaster/package.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
<depend>rclcpp_lifecycle</depend>
3434
<depend>realtime_tools</depend>
3535
<depend>generate_parameter_library</depend>
36+
<depend>tf2</depend>
37+
<depend>tf2_ros</depend>
38+
<depend>tf2_geometry_msgs</depend>
3639

3740
<test_depend>ament_cmake_gmock</test_depend>
3841
<test_depend>controller_manager</test_depend>

0 commit comments

Comments
 (0)