Skip to content

Commit deebbc3

Browse files
authored
Add new node interface TypeDescriptionsInterface to provide GetTypeDescription service (#2224)
* TypeDescriptions interface with readonly param configuration * Add parameter descriptor, to make read only * example of spinning in thread for get_type_description service * Add a basic test for the new interface * Fix tests with new parameter * Add comments about builtin parameters Signed-off-by: Emerson Knapp <[email protected]> Signed-off-by: William Woodall <[email protected]>
1 parent 588dba7 commit deebbc3

File tree

15 files changed

+400
-17
lines changed

15 files changed

+400
-17
lines changed

rclcpp/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ set(${PROJECT_NAME}_SRCS
9292
src/rclcpp/node_interfaces/node_time_source.cpp
9393
src/rclcpp/node_interfaces/node_timers.cpp
9494
src/rclcpp/node_interfaces/node_topics.cpp
95+
src/rclcpp/node_interfaces/node_type_descriptions.cpp
9596
src/rclcpp/node_interfaces/node_waitables.cpp
9697
src/rclcpp/node_options.cpp
9798
src/rclcpp/parameter.cpp

rclcpp/include/rclcpp/node.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#include "rclcpp/node_interfaces/node_time_source_interface.hpp"
5757
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
5858
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
59+
#include "rclcpp/node_interfaces/node_type_descriptions_interface.hpp"
5960
#include "rclcpp/node_interfaces/node_waitables_interface.hpp"
6061
#include "rclcpp/node_options.hpp"
6162
#include "rclcpp/parameter.hpp"
@@ -1456,6 +1457,11 @@ class Node : public std::enable_shared_from_this<Node>
14561457
rclcpp::node_interfaces::NodeTimeSourceInterface::SharedPtr
14571458
get_node_time_source_interface();
14581459

1460+
/// Return the Node's internal NodeTypeDescriptionsInterface implementation.
1461+
RCLCPP_PUBLIC
1462+
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr
1463+
get_node_type_descriptions_interface();
1464+
14591465
/// Return the sub-namespace, if this is a sub-node, otherwise an empty string.
14601466
/**
14611467
* The returned sub-namespace is either the accumulated sub-namespaces which
@@ -1588,6 +1594,7 @@ class Node : public std::enable_shared_from_this<Node>
15881594
rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock_;
15891595
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters_;
15901596
rclcpp::node_interfaces::NodeTimeSourceInterface::SharedPtr node_time_source_;
1597+
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr node_type_descriptions_;
15911598
rclcpp::node_interfaces::NodeWaitablesInterface::SharedPtr node_waitables_;
15921599

15931600
const rclcpp::NodeOptions node_options_;

rclcpp/include/rclcpp/node_interfaces/node_interfaces.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
rclcpp::node_interfaces::NodeTimeSourceInterface, \
3131
rclcpp::node_interfaces::NodeTimersInterface, \
3232
rclcpp::node_interfaces::NodeTopicsInterface, \
33+
rclcpp::node_interfaces::NodeTypeDescriptionsInterface, \
3334
rclcpp::node_interfaces::NodeWaitablesInterface
3435

3536

@@ -118,6 +119,7 @@ class NodeInterfaces
118119
* - rclcpp::node_interfaces::NodeTimeSourceInterface
119120
* - rclcpp::node_interfaces::NodeTimersInterface
120121
* - rclcpp::node_interfaces::NodeTopicsInterface
122+
* - rclcpp::node_interfaces::NodeTypeDescriptionsInterface
121123
* - rclcpp::node_interfaces::NodeWaitablesInterface
122124
*
123125
* Or you use custom interfaces as long as you make a template specialization
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright 2023 Open Source Robotics Foundation, Inc.
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+
#ifndef RCLCPP__NODE_INTERFACES__NODE_TYPE_DESCRIPTIONS_HPP_
16+
#define RCLCPP__NODE_INTERFACES__NODE_TYPE_DESCRIPTIONS_HPP_
17+
18+
#include <memory>
19+
20+
#include "rclcpp/macros.hpp"
21+
#include "rclcpp/node_interfaces/node_base_interface.hpp"
22+
#include "rclcpp/node_interfaces/node_logging_interface.hpp"
23+
#include "rclcpp/node_interfaces/node_parameters_interface.hpp"
24+
#include "rclcpp/node_interfaces/node_services_interface.hpp"
25+
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
26+
#include "rclcpp/node_interfaces/node_type_descriptions_interface.hpp"
27+
#include "rclcpp/visibility_control.hpp"
28+
29+
namespace rclcpp
30+
{
31+
namespace node_interfaces
32+
{
33+
34+
/// Implementation of the NodeTypeDescriptions part of the Node API.
35+
class NodeTypeDescriptions : public NodeTypeDescriptionsInterface
36+
{
37+
public:
38+
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeTypeDescriptions)
39+
40+
RCLCPP_PUBLIC
41+
explicit NodeTypeDescriptions(
42+
NodeBaseInterface::SharedPtr node_base,
43+
NodeLoggingInterface::SharedPtr node_logging,
44+
NodeParametersInterface::SharedPtr node_parameters,
45+
NodeServicesInterface::SharedPtr node_services);
46+
47+
RCLCPP_PUBLIC
48+
virtual
49+
~NodeTypeDescriptions();
50+
51+
private:
52+
RCLCPP_DISABLE_COPY(NodeTypeDescriptions)
53+
54+
// Pimpl hides helper types and functions used for wrapping a C service, which would be
55+
// awkward to expose in this header.
56+
class NodeTypeDescriptionsImpl;
57+
std::unique_ptr<NodeTypeDescriptionsImpl> impl_;
58+
};
59+
60+
} // namespace node_interfaces
61+
} // namespace rclcpp
62+
63+
#endif // RCLCPP__NODE_INTERFACES__NODE_TYPE_DESCRIPTIONS_HPP_
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2023 Open Source Robotics Foundation, Inc.
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+
#ifndef RCLCPP__NODE_INTERFACES__NODE_TYPE_DESCRIPTIONS_INTERFACE_HPP_
16+
#define RCLCPP__NODE_INTERFACES__NODE_TYPE_DESCRIPTIONS_INTERFACE_HPP_
17+
18+
#include "rclcpp/macros.hpp"
19+
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
20+
#include "rclcpp/visibility_control.hpp"
21+
22+
namespace rclcpp
23+
{
24+
namespace node_interfaces
25+
{
26+
27+
/// Pure virtual interface class for the NodeTypeDescriptions part of the Node API.
28+
class NodeTypeDescriptionsInterface
29+
{
30+
public:
31+
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeTypeDescriptionsInterface)
32+
33+
RCLCPP_PUBLIC
34+
virtual
35+
~NodeTypeDescriptionsInterface() = default;
36+
};
37+
38+
} // namespace node_interfaces
39+
} // namespace rclcpp
40+
41+
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(
42+
rclcpp::node_interfaces::NodeTypeDescriptionsInterface, type_descriptions)
43+
44+
#endif // RCLCPP__NODE_INTERFACES__NODE_TYPE_DESCRIPTIONS_INTERFACE_HPP_

rclcpp/src/rclcpp/node.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "rclcpp/node_interfaces/node_time_source.hpp"
3737
#include "rclcpp/node_interfaces/node_timers.hpp"
3838
#include "rclcpp/node_interfaces/node_topics.hpp"
39+
#include "rclcpp/node_interfaces/node_type_descriptions.hpp"
3940
#include "rclcpp/node_interfaces/node_waitables.hpp"
4041
#include "rclcpp/qos_overriding_options.hpp"
4142

@@ -206,6 +207,12 @@ Node::Node(
206207
options.clock_qos(),
207208
options.use_clock_thread()
208209
)),
210+
node_type_descriptions_(new rclcpp::node_interfaces::NodeTypeDescriptions(
211+
node_base_,
212+
node_logging_,
213+
node_parameters_,
214+
node_services_
215+
)),
209216
node_waitables_(new rclcpp::node_interfaces::NodeWaitables(node_base_.get())),
210217
node_options_(options),
211218
sub_namespace_(""),
@@ -591,6 +598,12 @@ Node::get_node_topics_interface()
591598
return node_topics_;
592599
}
593600

601+
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr
602+
Node::get_node_type_descriptions_interface()
603+
{
604+
return node_type_descriptions_;
605+
}
606+
594607
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr
595608
Node::get_node_services_interface()
596609
{

rclcpp/src/rclcpp/node_interfaces/node_base.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "rclcpp/node_interfaces/node_base.hpp"
2121

2222
#include "rcl/arguments.h"
23+
#include "rcl/node_type_cache.h"
2324
#include "rclcpp/exceptions.hpp"
2425
#include "rcutils/logging_macros.h"
2526
#include "rmw/validate_namespace.h"
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
// Copyright 2023 Open Source Robotics Foundation, Inc.
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+
#include <memory>
16+
#include <string>
17+
#include <thread>
18+
19+
#include "rclcpp/node_interfaces/node_type_descriptions.hpp"
20+
#include "rclcpp/parameter_client.hpp"
21+
22+
#include "type_description_interfaces/srv/get_type_description.h"
23+
24+
namespace
25+
{
26+
// Helper wrapper for rclcpp::Service to access ::Request and ::Response types for allocation.
27+
struct GetTypeDescription__C
28+
{
29+
using Request = type_description_interfaces__srv__GetTypeDescription_Request;
30+
using Response = type_description_interfaces__srv__GetTypeDescription_Response;
31+
using Event = type_description_interfaces__srv__GetTypeDescription_Event;
32+
};
33+
} // namespace
34+
35+
// Helper function for C typesupport.
36+
namespace rosidl_typesupport_cpp
37+
{
38+
template<>
39+
rosidl_service_type_support_t const *
40+
get_service_type_support_handle<GetTypeDescription__C>()
41+
{
42+
return ROSIDL_GET_SRV_TYPE_SUPPORT(type_description_interfaces, srv, GetTypeDescription);
43+
}
44+
} // namespace rosidl_typesupport_cpp
45+
46+
namespace rclcpp
47+
{
48+
namespace node_interfaces
49+
{
50+
51+
class NodeTypeDescriptions::NodeTypeDescriptionsImpl
52+
{
53+
public:
54+
using ServiceT = GetTypeDescription__C;
55+
56+
rclcpp::Logger logger_;
57+
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_;
58+
rclcpp::Service<ServiceT>::SharedPtr type_description_srv_;
59+
60+
NodeTypeDescriptionsImpl(
61+
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
62+
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
63+
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters,
64+
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services)
65+
: logger_(node_logging->get_logger()),
66+
node_base_(node_base)
67+
{
68+
const std::string enable_param_name = "start_type_description_service";
69+
70+
bool enabled = false;
71+
try {
72+
auto enable_param = node_parameters->declare_parameter(
73+
enable_param_name,
74+
rclcpp::ParameterValue(true),
75+
rcl_interfaces::msg::ParameterDescriptor()
76+
.set__name(enable_param_name)
77+
.set__type(rclcpp::PARAMETER_BOOL)
78+
.set__description("Start the ~/get_type_description service for this node.")
79+
.set__read_only(true));
80+
enabled = enable_param.get<bool>();
81+
} catch (const rclcpp::exceptions::InvalidParameterTypeException & exc) {
82+
RCLCPP_ERROR(logger_, "%s", exc.what());
83+
throw;
84+
}
85+
86+
if (enabled) {
87+
auto rcl_node = node_base->get_rcl_node_handle();
88+
rcl_ret_t rcl_ret = rcl_node_type_description_service_init(rcl_node);
89+
if (rcl_ret != RCL_RET_OK) {
90+
RCLCPP_ERROR(
91+
logger_, "Failed to initialize ~/get_type_description_service: %s",
92+
rcl_get_error_string().str);
93+
throw std::runtime_error(
94+
"Failed to initialize ~/get_type_description service.");
95+
}
96+
97+
rcl_service_t * rcl_srv = nullptr;
98+
rcl_ret = rcl_node_get_type_description_service(rcl_node, &rcl_srv);
99+
if (rcl_ret != RCL_RET_OK) {
100+
throw std::runtime_error(
101+
"Failed to get initialized ~/get_type_description service from rcl.");
102+
}
103+
104+
rclcpp::AnyServiceCallback<ServiceT> cb;
105+
cb.set(
106+
[this](
107+
std::shared_ptr<rmw_request_id_t> header,
108+
std::shared_ptr<ServiceT::Request> request,
109+
std::shared_ptr<ServiceT::Response> response
110+
) {
111+
rcl_node_type_description_service_handle_request(
112+
node_base_->get_rcl_node_handle(),
113+
header.get(),
114+
request.get(),
115+
response.get());
116+
});
117+
118+
type_description_srv_ = std::make_shared<Service<ServiceT>>(
119+
node_base_->get_shared_rcl_node_handle(),
120+
rcl_srv,
121+
cb);
122+
node_services->add_service(
123+
std::dynamic_pointer_cast<ServiceBase>(type_description_srv_),
124+
nullptr);
125+
}
126+
}
127+
128+
~NodeTypeDescriptionsImpl()
129+
{
130+
if (
131+
type_description_srv_ &&
132+
RCL_RET_OK != rcl_node_type_description_service_fini(node_base_->get_rcl_node_handle()))
133+
{
134+
RCLCPP_ERROR(
135+
logger_,
136+
"Error in shutdown of get_type_description service: %s", rcl_get_error_string().str);
137+
}
138+
}
139+
};
140+
141+
NodeTypeDescriptions::NodeTypeDescriptions(
142+
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
143+
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
144+
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters,
145+
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services)
146+
: impl_(new NodeTypeDescriptionsImpl(
147+
node_base,
148+
node_logging,
149+
node_parameters,
150+
node_services))
151+
{}
152+
153+
NodeTypeDescriptions::~NodeTypeDescriptions()
154+
{}
155+
156+
} // namespace node_interfaces
157+
} // namespace rclcpp

rclcpp/test/rclcpp/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,11 @@ if(TARGET test_node_interfaces__node_topics)
262262
"test_msgs")
263263
target_link_libraries(test_node_interfaces__node_topics ${PROJECT_NAME} mimick)
264264
endif()
265+
ament_add_gtest(test_node_interfaces__node_type_descriptions
266+
node_interfaces/test_node_type_descriptions.cpp)
267+
if(TARGET test_node_interfaces__node_type_descriptions)
268+
target_link_libraries(test_node_interfaces__node_type_descriptions ${PROJECT_NAME} mimick)
269+
endif()
265270
ament_add_gtest(test_node_interfaces__node_waitables
266271
node_interfaces/test_node_waitables.cpp)
267272
if(TARGET test_node_interfaces__node_waitables)

rclcpp/test/rclcpp/node_interfaces/test_node_parameters.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ TEST_F(TestNodeParameters, list_parameters)
7777
std::vector<std::string> prefixes;
7878
const auto list_result = node_parameters->list_parameters(prefixes, 1u);
7979

80-
// Currently the only default parameter is 'use_sim_time', but that may change.
80+
// Currently the default parameters are 'use_sim_time' and 'start_type_description_service'
8181
size_t number_of_parameters = list_result.names.size();
82-
EXPECT_GE(1u, number_of_parameters);
82+
EXPECT_GE(2u, number_of_parameters);
8383

8484
const std::string parameter_name = "new_parameter";
8585
const rclcpp::ParameterValue value(true);

0 commit comments

Comments
 (0)