Skip to content

Commit 7a5d0ad

Browse files
committed
srdf_publisher_node
1 parent 47ce660 commit 7a5d0ad

File tree

5 files changed

+246
-0
lines changed

5 files changed

+246
-0
lines changed

moveit_ros/planning/CMakeLists.txt

+10
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ find_package(moveit_msgs REQUIRED)
1616
find_package(moveit_ros_occupancy_map_monitor REQUIRED)
1717
find_package(pluginlib REQUIRED)
1818
find_package(rclcpp REQUIRED)
19+
find_package(rclcpp_components REQUIRED)
1920
find_package(srdfdom REQUIRED)
21+
find_package(std_msgs REQUIRED)
2022
find_package(tf2 REQUIRED)
2123
find_package(tf2_eigen REQUIRED)
2224
find_package(tf2_geometry_msgs REQUIRED)
@@ -59,6 +61,7 @@ set(THIS_PACKAGE_LIBRARIES
5961
moveit_robot_model_loader
6062
moveit_trajectory_execution_manager
6163
planning_pipeline_parameters
64+
srdf_publisher_node
6265
)
6366

6467
set(THIS_PACKAGE_INCLUDE_DEPENDS
@@ -70,7 +73,9 @@ set(THIS_PACKAGE_INCLUDE_DEPENDS
7073
moveit_ros_occupancy_map_monitor
7174
pluginlib
7275
rclcpp
76+
rclcpp_components
7377
srdfdom
78+
std_msgs
7479
tf2
7580
tf2_eigen
7681
tf2_geometry_msgs
@@ -97,6 +102,7 @@ add_subdirectory(planning_response_adapter_plugins)
97102
add_subdirectory(planning_scene_monitor)
98103
add_subdirectory(rdf_loader)
99104
add_subdirectory(robot_model_loader)
105+
add_subdirectory(srdf_publisher_node)
100106
add_subdirectory(trajectory_execution_manager)
101107

102108
install(
@@ -111,6 +117,10 @@ install(
111117
ament_export_targets(moveit_ros_planningTargets HAS_LIBRARY_TARGET)
112118
ament_export_dependencies(${THIS_PACKAGE_INCLUDE_DEPENDS})
113119

120+
rclcpp_components_register_node(srdf_publisher_node
121+
PLUGIN "moveit_ros_planning::SrdfPublisher"
122+
EXECUTABLE srdf_publisher)
123+
114124
pluginlib_export_plugin_description_file(moveit_core "default_request_adapters_plugin_description.xml")
115125
pluginlib_export_plugin_description_file(moveit_core "default_response_adapters_plugin_description.xml")
116126
if(BUILD_TESTING)

moveit_ros/planning/package.xml

+2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@
3434
<depend>moveit_msgs</depend>
3535
<depend>moveit_ros_occupancy_map_monitor</depend>
3636
<depend>rclcpp_action</depend>
37+
<depend>rclcpp_components</depend>
3738
<depend>rclcpp</depend>
3839
<depend>srdfdom</depend>
40+
<depend>std_msgs</depend>
3941
<depend>tf2_eigen</depend>
4042
<depend>tf2_geometry_msgs</depend>
4143
<depend>tf2_msgs</depend>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
add_library(srdf_publisher_node SHARED src/srdf_publisher_node.cpp)
2+
ament_target_dependencies(srdf_publisher_node PUBLIC
3+
std_msgs
4+
rclcpp
5+
rclcpp_components
6+
)
7+
8+
if(BUILD_TESTING)
9+
find_package(launch_testing_ament_cmake)
10+
11+
add_launch_test(test/srdf_publisher_test.py
12+
TARGET test-srdf_publisher
13+
)
14+
endif()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*********************************************************************
2+
* Software License Agreement (BSD License)
3+
*
4+
* Copyright (c) 2024, PickNik Robotics Inc.
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions
9+
* are met:
10+
*
11+
* * Redistributions of source code must retain the above copyright
12+
* notice, this list of conditions and the following disclaimer.
13+
* * Redistributions in binary form must reproduce the above
14+
* copyright notice, this list of conditions and the following
15+
* disclaimer in the documentation and/or other materials provided
16+
* with the distribution.
17+
* * Neither the name of PickNik Robotics Inc. nor the names of its
18+
* contributors may be used to endorse or promote products derived
19+
* from this software without specific prior written permission.
20+
*
21+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24+
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25+
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27+
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31+
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32+
* POSSIBILITY OF SUCH DAMAGE.
33+
*********************************************************************/
34+
35+
// SrdfPublisher Node
36+
// Author: Tyler Weaver
37+
//
38+
// Node with a single parameter and single publisher using transient local QoS.
39+
// Publishes string set on parameter `robot_description_semantic` to topic
40+
// `/robot_description_semantic`.
41+
//
42+
// This is similar to what [robot_state_publisher](https://github.com/ros/robot_state_publisher)
43+
// does for the URDF using parameter `robot_description` and topic `/robot_description`.
44+
//
45+
// As MoveIt subscribes to the topic `/robot_description_semantic` for the srdf
46+
// this node can be used when you want to set the SRDF parameter on only one node
47+
// and have the rest of your system use a subscriber to that topic to get the
48+
// SRDF.
49+
50+
#include <rclcpp/rclcpp.hpp>
51+
#include <std_msgs/msg/string.hpp>
52+
53+
#include <string>
54+
55+
namespace moveit_ros_planning
56+
{
57+
58+
class SrdfPublisher : public rclcpp::Node
59+
{
60+
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr srdf_publisher_;
61+
rclcpp::node_interfaces::OnSetParametersCallbackHandle::SharedPtr on_set_parameters_handle_;
62+
63+
public:
64+
SrdfPublisher(const rclcpp::NodeOptions& options) : rclcpp::Node("srdf_publisher", options)
65+
{
66+
srdf_publisher_ = this->create_publisher<std_msgs::msg::String>("robot_description_semantic",
67+
rclcpp::QoS(1).transient_local().reliable());
68+
on_set_parameters_handle_ =
69+
this->add_on_set_parameters_callback([this](const std::vector<rclcpp::Parameter>& parameters) {
70+
for (auto const& parameter : parameters)
71+
{
72+
if (parameter.get_name() == "robot_description_semantic")
73+
{
74+
std_msgs::msg::String msg;
75+
msg.data = parameter.get_value<std::string>();
76+
srdf_publisher_->publish(msg);
77+
}
78+
}
79+
80+
rcl_interfaces::msg::SetParametersResult result;
81+
result.successful = true;
82+
return result;
83+
});
84+
85+
rcl_interfaces::msg::ParameterDescriptor descriptor;
86+
descriptor.type = rcl_interfaces::msg::ParameterType::PARAMETER_STRING;
87+
descriptor.description = "Semantic Robot Description Format";
88+
this->declare_parameter("robot_description_semantic", rclcpp::ParameterType::PARAMETER_STRING, descriptor);
89+
}
90+
};
91+
92+
} // namespace moveit_ros_planning
93+
94+
#include "rclcpp_components/register_node_macro.hpp"
95+
RCLCPP_COMPONENTS_REGISTER_NODE(moveit_ros_planning::SrdfPublisher)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# Software License Agreement (BSD License)
2+
#
3+
# Copyright (c) 2024, PickNik Robotics Inc.
4+
# All rights reserved.
5+
#
6+
# Redistribution and use in source and binary forms, with or without
7+
# modification, are permitted provided that the following conditions
8+
# are met:
9+
#
10+
# # Redistributions of source code must retain the above copyright
11+
# notice, this list of conditions and the following disclaimer.
12+
# # Redistributions in binary form must reproduce the above
13+
# copyright notice, this list of conditions and the following
14+
# disclaimer in the documentation and/or other materials provided
15+
# with the distribution.
16+
# # Neither the name of Willow Garage nor the names of its
17+
# contributors may be used to endorse or promote products derived
18+
# from this software without specific prior written permission.
19+
#
20+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23+
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24+
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25+
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26+
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29+
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30+
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31+
# POSSIBILITY OF SUCH DAMAGE.
32+
33+
# Author: Tyler Weaver
34+
35+
import unittest
36+
from threading import Event
37+
from threading import Thread
38+
39+
import launch
40+
import launch_ros
41+
import launch_testing
42+
import rclpy
43+
from rclpy.node import Node
44+
from rclpy.qos import (
45+
QoSProfile,
46+
QoSReliabilityPolicy,
47+
QoSDurabilityPolicy,
48+
)
49+
from std_msgs.msg import String
50+
51+
import pytest
52+
53+
54+
@pytest.mark.launch_test
55+
def generate_test_description():
56+
# dut: device under test
57+
srdf_publisher = launch_ros.actions.Node(
58+
package="moveit_ros_planning",
59+
parameters=[{"robot_description_semantic": "test value"}],
60+
executable="srdf_publisher",
61+
output="screen",
62+
)
63+
64+
return launch.LaunchDescription(
65+
[
66+
srdf_publisher,
67+
# Start tests right away - no need to wait for anything
68+
launch_testing.actions.ReadyToTest(),
69+
]
70+
), {"srdf_publisher": srdf_publisher}
71+
72+
73+
class SrdfObserverNode(Node):
74+
def __init__(self, name="srdf_observer_node"):
75+
super().__init__(name)
76+
self.msg_event_object = Event()
77+
self.srdf = ""
78+
79+
def start_subscriber(self):
80+
# Create a subscriber
81+
self.subscription = self.create_subscription(
82+
String,
83+
"robot_description_semantic",
84+
self.subscriber_callback,
85+
qos_profile=QoSProfile(
86+
reliability=QoSReliabilityPolicy.RELIABLE,
87+
durability=QoSDurabilityPolicy.TRANSIENT_LOCAL,
88+
depth=1,
89+
),
90+
)
91+
92+
# Add a spin thread
93+
self.ros_spin_thread = Thread(
94+
target=lambda node: rclpy.spin(node), args=(self,)
95+
)
96+
self.ros_spin_thread.start()
97+
98+
def subscriber_callback(self, msg):
99+
self.srdf = msg.data
100+
self.msg_event_object.set()
101+
102+
103+
# These tests will run concurrently with the dut process. After all these tests are done,
104+
# the launch system will shut down the processes that it started up
105+
class TestFixture(unittest.TestCase):
106+
def test_rosout_msgs_published(self, proc_output):
107+
rclpy.init()
108+
try:
109+
node = SrdfObserverNode()
110+
node.start_subscriber()
111+
msgs_received_flag = node.msg_event_object.wait(timeout=5.0)
112+
assert (
113+
msgs_received_flag
114+
), "Did not receive message on `/robot_description_semantic`!"
115+
assert node.srdf == "test value"
116+
finally:
117+
rclpy.shutdown()
118+
119+
120+
@launch_testing.post_shutdown_test()
121+
class TestProcessOutput(unittest.TestCase):
122+
def test_exit_code(self, proc_info):
123+
# Check that all processes in the launch (in this case, there's just one) exit
124+
# with code 0
125+
launch_testing.asserts.assertExitCodes(proc_info)

0 commit comments

Comments
 (0)