Compare commits
25 Commits
rclcpp_wai
...
22.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89f0afe9bc | ||
|
|
a4db4c57a6 | ||
|
|
fbe8f28cd1 | ||
|
|
65f0b70d4a | ||
|
|
9b4b3da3d4 | ||
|
|
cd0440f1a5 | ||
|
|
a17d26b20a | ||
|
|
e2965831d5 | ||
|
|
ea29c142af | ||
|
|
5d6e5fa766 | ||
|
|
22a954e1b0 | ||
|
|
c0d72c3ee0 | ||
|
|
6e97990a32 | ||
|
|
4ebc5f61d8 | ||
|
|
a7a9b78fee | ||
|
|
945d254e32 | ||
|
|
deebbc3ad6 | ||
|
|
588dba7a70 | ||
|
|
2e355e4849 | ||
|
|
fe2e0e4c64 | ||
|
|
005f6aefe9 | ||
|
|
3a64349aec | ||
|
|
3530b0959c | ||
|
|
4d12bcbca0 | ||
|
|
1fff79089a |
@@ -2,6 +2,37 @@
|
||||
Changelog for package rclcpp
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
22.1.0 (2023-08-21)
|
||||
-------------------
|
||||
* Do not crash Executor when send_response fails due to client failure. (`#2276 <https://github.com/ros2/rclcpp/issues/2276>`_)
|
||||
* Adding Custom Unknown Type Error (`#2272 <https://github.com/ros2/rclcpp/issues/2272>`_)
|
||||
* Add a pimpl inside rclcpp::Node for future distro backports (`#2228 <https://github.com/ros2/rclcpp/issues/2228>`_)
|
||||
* Remove an unused variable from the events executor tests. (`#2270 <https://github.com/ros2/rclcpp/issues/2270>`_)
|
||||
* Add spin_all shortcut (`#2246 <https://github.com/ros2/rclcpp/issues/2246>`_)
|
||||
* Adding Missing Group Exceptions (`#2256 <https://github.com/ros2/rclcpp/issues/2256>`_)
|
||||
* Change associated clocks storage to unordered_set (`#2257 <https://github.com/ros2/rclcpp/issues/2257>`_)
|
||||
* associated clocks should be protected by mutex. (`#2255 <https://github.com/ros2/rclcpp/issues/2255>`_)
|
||||
* Instrument loaned message publication code path (`#2240 <https://github.com/ros2/rclcpp/issues/2240>`_)
|
||||
* Contributors: Chris Lalancette, Christophe Bedard, Emerson Knapp, Luca Della Vedova, Lucas Wendland, Tomoya Fujita, Tony Najjar
|
||||
|
||||
22.0.0 (2023-07-11)
|
||||
-------------------
|
||||
* Implement get_node_type_descriptions_interface for lifecyclenode and add smoke test for it (`#2237 <https://github.com/ros2/rclcpp/issues/2237>`_)
|
||||
* Add new node interface TypeDescriptionsInterface to provide GetTypeDescription service (`#2224 <https://github.com/ros2/rclcpp/issues/2224>`_)
|
||||
* Move always_false_v to detail namespace (`#2232 <https://github.com/ros2/rclcpp/issues/2232>`_)
|
||||
* Revamp the test_subscription.cpp tests. (`#2227 <https://github.com/ros2/rclcpp/issues/2227>`_)
|
||||
* warning: comparison of integer expressions of different signedness (`#2219 <https://github.com/ros2/rclcpp/issues/2219>`_)
|
||||
* Modifies timers API to select autostart state (`#2005 <https://github.com/ros2/rclcpp/issues/2005>`_)
|
||||
* Enable callback group tests for connextdds (`#2182 <https://github.com/ros2/rclcpp/issues/2182>`_)
|
||||
* Contributors: Chris Lalancette, Christopher Wecht, Eloy Briceno, Emerson Knapp, Nathan Wiebe Neufeldt, Tomoya Fujita
|
||||
|
||||
21.3.0 (2023-06-12)
|
||||
-------------------
|
||||
* Fix up misspellings of "receive". (`#2208 <https://github.com/ros2/rclcpp/issues/2208>`_)
|
||||
* Remove flaky stressAddRemoveNode test (`#2206 <https://github.com/ros2/rclcpp/issues/2206>`_)
|
||||
* Use TRACETOOLS\_ prefix for tracepoint-related macros (`#2162 <https://github.com/ros2/rclcpp/issues/2162>`_)
|
||||
* Contributors: Chris Lalancette, Christophe Bedard, Michael Carroll
|
||||
|
||||
21.2.0 (2023-06-07)
|
||||
-------------------
|
||||
* remove nolint since ament_cpplint updated for the c++17 header (`#2198 <https://github.com/ros2/rclcpp/issues/2198>`_)
|
||||
|
||||
@@ -92,6 +92,7 @@ set(${PROJECT_NAME}_SRCS
|
||||
src/rclcpp/node_interfaces/node_time_source.cpp
|
||||
src/rclcpp/node_interfaces/node_timers.cpp
|
||||
src/rclcpp/node_interfaces/node_topics.cpp
|
||||
src/rclcpp/node_interfaces/node_type_descriptions.cpp
|
||||
src/rclcpp/node_interfaces/node_waitables.cpp
|
||||
src/rclcpp/node_options.cpp
|
||||
src/rclcpp/parameter.cpp
|
||||
|
||||
@@ -34,15 +34,15 @@
|
||||
#include "rclcpp/type_adapter.hpp"
|
||||
|
||||
|
||||
template<class>
|
||||
inline constexpr bool always_false_v = false;
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class>
|
||||
inline constexpr bool always_false_v = false;
|
||||
|
||||
template<typename MessageT, typename AllocatorT>
|
||||
struct MessageDeleterHelper
|
||||
{
|
||||
@@ -580,7 +580,7 @@ public:
|
||||
}
|
||||
// condition to catch unhandled callback types
|
||||
else { // NOLINT[readability/braces]
|
||||
static_assert(always_false_v<T>, "unhandled callback type");
|
||||
static_assert(detail::always_false_v<T>, "unhandled callback type");
|
||||
}
|
||||
}, callback_variant_);
|
||||
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
|
||||
@@ -660,7 +660,7 @@ public:
|
||||
}
|
||||
// condition to catch unhandled callback types
|
||||
else { // NOLINT[readability/braces]
|
||||
static_assert(always_false_v<T>, "unhandled callback type");
|
||||
static_assert(detail::always_false_v<T>, "unhandled callback type");
|
||||
}
|
||||
}, callback_variant_);
|
||||
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
|
||||
@@ -790,7 +790,7 @@ public:
|
||||
}
|
||||
// condition to catch unhandled callback types
|
||||
else { // NOLINT[readability/braces]
|
||||
static_assert(always_false_v<T>, "unhandled callback type");
|
||||
static_assert(detail::always_false_v<T>, "unhandled callback type");
|
||||
}
|
||||
}, callback_variant_);
|
||||
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
|
||||
@@ -924,7 +924,7 @@ public:
|
||||
}
|
||||
// condition to catch unhandled callback types
|
||||
else { // NOLINT[readability/braces]
|
||||
static_assert(always_false_v<T>, "unhandled callback type");
|
||||
static_assert(detail::always_false_v<T>, "unhandled callback type");
|
||||
}
|
||||
}, callback_variant_);
|
||||
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
|
||||
|
||||
@@ -90,7 +90,8 @@ create_timer(
|
||||
rclcpp::Clock::SharedPtr clock,
|
||||
rclcpp::Duration period,
|
||||
CallbackT && callback,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr)
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr,
|
||||
bool autostart = true)
|
||||
{
|
||||
return create_timer(
|
||||
clock,
|
||||
@@ -98,7 +99,8 @@ create_timer(
|
||||
std::forward<CallbackT>(callback),
|
||||
group,
|
||||
node_base.get(),
|
||||
node_timers.get());
|
||||
node_timers.get(),
|
||||
autostart);
|
||||
}
|
||||
|
||||
/// Create a timer with a given clock
|
||||
@@ -109,7 +111,8 @@ create_timer(
|
||||
rclcpp::Clock::SharedPtr clock,
|
||||
rclcpp::Duration period,
|
||||
CallbackT && callback,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr)
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr,
|
||||
bool autostart = true)
|
||||
{
|
||||
return create_timer(
|
||||
clock,
|
||||
@@ -117,7 +120,8 @@ create_timer(
|
||||
std::forward<CallbackT>(callback),
|
||||
group,
|
||||
rclcpp::node_interfaces::get_node_base_interface(node).get(),
|
||||
rclcpp::node_interfaces::get_node_timers_interface(node).get());
|
||||
rclcpp::node_interfaces::get_node_timers_interface(node).get(),
|
||||
autostart);
|
||||
}
|
||||
|
||||
/// Convenience method to create a general timer with node resources.
|
||||
@@ -132,6 +136,7 @@ create_timer(
|
||||
* \param group callback group
|
||||
* \param node_base node base interface
|
||||
* \param node_timers node timer interface
|
||||
* \param autostart defines if the timer should start it's countdown on initialization or not.
|
||||
* \return shared pointer to a generic timer
|
||||
* \throws std::invalid_argument if either clock, node_base or node_timers
|
||||
* are nullptr, or period is negative or too large
|
||||
@@ -144,7 +149,8 @@ create_timer(
|
||||
CallbackT callback,
|
||||
rclcpp::CallbackGroup::SharedPtr group,
|
||||
node_interfaces::NodeBaseInterface * node_base,
|
||||
node_interfaces::NodeTimersInterface * node_timers)
|
||||
node_interfaces::NodeTimersInterface * node_timers,
|
||||
bool autostart = true)
|
||||
{
|
||||
if (clock == nullptr) {
|
||||
throw std::invalid_argument{"clock cannot be null"};
|
||||
@@ -160,7 +166,7 @@ create_timer(
|
||||
|
||||
// Add a new generic timer.
|
||||
auto timer = rclcpp::GenericTimer<CallbackT>::make_shared(
|
||||
std::move(clock), period_ns, std::move(callback), node_base->get_context());
|
||||
std::move(clock), period_ns, std::move(callback), node_base->get_context(), autostart);
|
||||
node_timers->add_timer(timer, group);
|
||||
return timer;
|
||||
}
|
||||
@@ -187,7 +193,8 @@ create_wall_timer(
|
||||
CallbackT callback,
|
||||
rclcpp::CallbackGroup::SharedPtr group,
|
||||
node_interfaces::NodeBaseInterface * node_base,
|
||||
node_interfaces::NodeTimersInterface * node_timers)
|
||||
node_interfaces::NodeTimersInterface * node_timers,
|
||||
bool autostart = true)
|
||||
{
|
||||
if (node_base == nullptr) {
|
||||
throw std::invalid_argument{"input node_base cannot be null"};
|
||||
@@ -201,7 +208,7 @@ create_wall_timer(
|
||||
|
||||
// Add a new wall timer.
|
||||
auto timer = rclcpp::WallTimer<CallbackT>::make_shared(
|
||||
period_ns, std::move(callback), node_base->get_context());
|
||||
period_ns, std::move(callback), node_base->get_context(), autostart);
|
||||
node_timers->add_timer(timer, group);
|
||||
return timer;
|
||||
}
|
||||
|
||||
@@ -206,6 +206,14 @@ public:
|
||||
const std::vector<std::string> unknown_ros_args;
|
||||
};
|
||||
|
||||
/// Thrown when an unknown type is passed
|
||||
class UnknownTypeError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit UnknownTypeError(const std::string & type)
|
||||
: std::runtime_error("Unknown type: " + type) {}
|
||||
};
|
||||
|
||||
/// Thrown when an invalid rclcpp::Event object or SharedPtr is encountered.
|
||||
class InvalidEventError : public std::runtime_error
|
||||
{
|
||||
@@ -222,6 +230,14 @@ public:
|
||||
: std::runtime_error("event already registered") {}
|
||||
};
|
||||
|
||||
/// Thrown when a callback group is missing from the node, when it wants to utilize the group.
|
||||
class MissingGroupNodeException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit MissingGroupNodeException(const std::string & obj_type)
|
||||
: std::runtime_error("cannot create: " + obj_type + " , callback group not in node") {}
|
||||
};
|
||||
|
||||
/// Thrown if passed parameters are inconsistent or invalid
|
||||
class InvalidParametersException : public std::runtime_error
|
||||
{
|
||||
|
||||
@@ -297,6 +297,21 @@ public:
|
||||
virtual void
|
||||
spin_some(std::chrono::nanoseconds max_duration = std::chrono::nanoseconds(0));
|
||||
|
||||
/// Add a node, complete all immediately available work exhaustively, and remove the node.
|
||||
/**
|
||||
* \param[in] node Shared pointer to the node to add.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_node_all(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
|
||||
std::chrono::nanoseconds max_duration);
|
||||
|
||||
/// Convenience function which takes Node and forwards NodeBaseInterface.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_node_all(std::shared_ptr<rclcpp::Node> node, std::chrono::nanoseconds max_duration);
|
||||
|
||||
/// Collect and execute work repeatedly within a duration or until no more work is available.
|
||||
/**
|
||||
* This function can be overridden. The default implementation is suitable for a
|
||||
|
||||
@@ -29,6 +29,18 @@
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
/// Create a default single-threaded executor and execute all available work exhaustively.
|
||||
/** \param[in] node_ptr Shared pointer to the node to spin. */
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_all(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
|
||||
std::chrono::nanoseconds max_duration);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_all(rclcpp::Node::SharedPtr node_ptr, std::chrono::nanoseconds max_duration);
|
||||
|
||||
/// Create a default single-threaded executor and execute any immediately available work.
|
||||
/** \param[in] node_ptr Shared pointer to the node to spin. */
|
||||
RCLCPP_PUBLIC
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include "rclcpp/node_interfaces/node_time_source_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_type_descriptions_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_waitables_interface.hpp"
|
||||
#include "rclcpp/node_options.hpp"
|
||||
#include "rclcpp/parameter.hpp"
|
||||
@@ -232,13 +233,15 @@ public:
|
||||
* \param[in] period Time interval between triggers of the callback.
|
||||
* \param[in] callback User-defined callback function.
|
||||
* \param[in] group Callback group to execute this timer's callback in.
|
||||
* \param[in] autostart The state of the clock on initialization.
|
||||
*/
|
||||
template<typename DurationRepT = int64_t, typename DurationT = std::milli, typename CallbackT>
|
||||
typename rclcpp::WallTimer<CallbackT>::SharedPtr
|
||||
create_wall_timer(
|
||||
std::chrono::duration<DurationRepT, DurationT> period,
|
||||
CallbackT callback,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr);
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr,
|
||||
bool autostart = true);
|
||||
|
||||
/// Create a timer that uses the node clock to drive the callback.
|
||||
/**
|
||||
@@ -1454,6 +1457,11 @@ public:
|
||||
rclcpp::node_interfaces::NodeTimeSourceInterface::SharedPtr
|
||||
get_node_time_source_interface();
|
||||
|
||||
/// Return the Node's internal NodeTypeDescriptionsInterface implementation.
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr
|
||||
get_node_type_descriptions_interface();
|
||||
|
||||
/// Return the sub-namespace, if this is a sub-node, otherwise an empty string.
|
||||
/**
|
||||
* The returned sub-namespace is either the accumulated sub-namespaces which
|
||||
@@ -1586,11 +1594,18 @@ private:
|
||||
rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock_;
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters_;
|
||||
rclcpp::node_interfaces::NodeTimeSourceInterface::SharedPtr node_time_source_;
|
||||
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr node_type_descriptions_;
|
||||
rclcpp::node_interfaces::NodeWaitablesInterface::SharedPtr node_waitables_;
|
||||
|
||||
const rclcpp::NodeOptions node_options_;
|
||||
const std::string sub_namespace_;
|
||||
const std::string effective_namespace_;
|
||||
|
||||
class NodeImpl;
|
||||
// This member is meant to be a place to backport features into stable distributions,
|
||||
// and new features targeting Rolling should not use this.
|
||||
// See the comment in node.cpp for more information.
|
||||
std::shared_ptr<NodeImpl> hidden_impl_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -110,14 +110,16 @@ typename rclcpp::WallTimer<CallbackT>::SharedPtr
|
||||
Node::create_wall_timer(
|
||||
std::chrono::duration<DurationRepT, DurationT> period,
|
||||
CallbackT callback,
|
||||
rclcpp::CallbackGroup::SharedPtr group)
|
||||
rclcpp::CallbackGroup::SharedPtr group,
|
||||
bool autostart)
|
||||
{
|
||||
return rclcpp::create_wall_timer(
|
||||
period,
|
||||
std::move(callback),
|
||||
group,
|
||||
this->node_base_.get(),
|
||||
this->node_timers_.get());
|
||||
this->node_timers_.get(),
|
||||
autostart);
|
||||
}
|
||||
|
||||
template<typename DurationRepT, typename DurationT, typename CallbackT>
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
rclcpp::node_interfaces::NodeTimeSourceInterface, \
|
||||
rclcpp::node_interfaces::NodeTimersInterface, \
|
||||
rclcpp::node_interfaces::NodeTopicsInterface, \
|
||||
rclcpp::node_interfaces::NodeTypeDescriptionsInterface, \
|
||||
rclcpp::node_interfaces::NodeWaitablesInterface
|
||||
|
||||
|
||||
@@ -118,6 +119,7 @@ public:
|
||||
* - rclcpp::node_interfaces::NodeTimeSourceInterface
|
||||
* - rclcpp::node_interfaces::NodeTimersInterface
|
||||
* - rclcpp::node_interfaces::NodeTopicsInterface
|
||||
* - rclcpp::node_interfaces::NodeTypeDescriptionsInterface
|
||||
* - rclcpp::node_interfaces::NodeWaitablesInterface
|
||||
*
|
||||
* Or you use custom interfaces as long as you make a template specialization
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_TYPE_DESCRIPTIONS_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_TYPE_DESCRIPTIONS_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_logging_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_parameters_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_services_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_type_descriptions_interface.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
/// Implementation of the NodeTypeDescriptions part of the Node API.
|
||||
class NodeTypeDescriptions : public NodeTypeDescriptionsInterface
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeTypeDescriptions)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
explicit NodeTypeDescriptions(
|
||||
NodeBaseInterface::SharedPtr node_base,
|
||||
NodeLoggingInterface::SharedPtr node_logging,
|
||||
NodeParametersInterface::SharedPtr node_parameters,
|
||||
NodeServicesInterface::SharedPtr node_services);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
~NodeTypeDescriptions();
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(NodeTypeDescriptions)
|
||||
|
||||
// Pimpl hides helper types and functions used for wrapping a C service, which would be
|
||||
// awkward to expose in this header.
|
||||
class NodeTypeDescriptionsImpl;
|
||||
std::unique_ptr<NodeTypeDescriptionsImpl> impl_;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_TYPE_DESCRIPTIONS_HPP_
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_TYPE_DESCRIPTIONS_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_TYPE_DESCRIPTIONS_INTERFACE_HPP_
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
/// Pure virtual interface class for the NodeTypeDescriptions part of the Node API.
|
||||
class NodeTypeDescriptionsInterface
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeTypeDescriptionsInterface)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
~NodeTypeDescriptionsInterface() = default;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(
|
||||
rclcpp::node_interfaces::NodeTypeDescriptionsInterface, type_descriptions)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_TYPE_DESCRIPTIONS_INTERFACE_HPP_
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
*
|
||||
* Example Usage:
|
||||
*
|
||||
* If you have recieved a parameter event and are only interested in parameters foo and
|
||||
* If you have received a parameter event and are only interested in parameters foo and
|
||||
* bar being added or changed but don't care about deletion.
|
||||
*
|
||||
* ```cpp
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "rcl_interfaces/msg/parameter_type.hpp"
|
||||
#include "rcl_interfaces/msg/parameter_value.hpp"
|
||||
#include "rclcpp/exceptions/exceptions.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
|
||||
@@ -456,6 +456,7 @@ protected:
|
||||
do_loaned_message_publish(
|
||||
std::unique_ptr<ROSMessageType, std::function<void(ROSMessageType *)>> msg)
|
||||
{
|
||||
TRACETOOLS_TRACEPOINT(rclcpp_publish, nullptr, static_cast<const void *>(msg.get()));
|
||||
auto status = rcl_publish_loaned_message(publisher_handle_.get(), msg.get(), nullptr);
|
||||
|
||||
if (RCL_RET_PUBLISHER_INVALID == status) {
|
||||
|
||||
@@ -486,6 +486,14 @@ public:
|
||||
{
|
||||
rcl_ret_t ret = rcl_send_response(get_service_handle().get(), &req_id, &response);
|
||||
|
||||
if (ret == RCL_RET_TIMEOUT) {
|
||||
RCLCPP_WARN(
|
||||
node_logger_.get_child("rclcpp"),
|
||||
"failed to send response to %s (timeout): %s",
|
||||
this->get_service_name(), rcl_get_error_string().str);
|
||||
rcl_reset_error();
|
||||
return;
|
||||
}
|
||||
if (ret != RCL_RET_OK) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to send response");
|
||||
}
|
||||
|
||||
@@ -53,12 +53,17 @@ public:
|
||||
* \param clock A clock to use for time and sleeping
|
||||
* \param period The interval at which the timer fires
|
||||
* \param context node context
|
||||
* \param autostart timer state on initialization
|
||||
*
|
||||
* In order to activate a timer that is not started on initialization,
|
||||
* user should call the reset() method.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
explicit TimerBase(
|
||||
Clock::SharedPtr clock,
|
||||
std::chrono::nanoseconds period,
|
||||
rclcpp::Context::SharedPtr context);
|
||||
rclcpp::Context::SharedPtr context,
|
||||
bool autostart = true);
|
||||
|
||||
/// TimerBase destructor
|
||||
RCLCPP_PUBLIC
|
||||
@@ -216,12 +221,13 @@ public:
|
||||
* \param[in] period The interval at which the timer fires.
|
||||
* \param[in] callback User-specified callback function.
|
||||
* \param[in] context custom context to be used.
|
||||
* \param autostart timer state on initialization
|
||||
*/
|
||||
explicit GenericTimer(
|
||||
Clock::SharedPtr clock, std::chrono::nanoseconds period, FunctorT && callback,
|
||||
rclcpp::Context::SharedPtr context
|
||||
rclcpp::Context::SharedPtr context, bool autostart = true
|
||||
)
|
||||
: TimerBase(clock, period, context), callback_(std::forward<FunctorT>(callback))
|
||||
: TimerBase(clock, period, context, autostart), callback_(std::forward<FunctorT>(callback))
|
||||
{
|
||||
TRACETOOLS_TRACEPOINT(
|
||||
rclcpp_timer_callback_added,
|
||||
@@ -330,13 +336,15 @@ public:
|
||||
* \param period The interval at which the timer fires
|
||||
* \param callback The callback function to execute every interval
|
||||
* \param context node context
|
||||
* \param autostart timer state on initialization
|
||||
*/
|
||||
WallTimer(
|
||||
std::chrono::nanoseconds period,
|
||||
FunctorT && callback,
|
||||
rclcpp::Context::SharedPtr context)
|
||||
rclcpp::Context::SharedPtr context,
|
||||
bool autostart = true)
|
||||
: GenericTimer<FunctorT>(
|
||||
std::make_shared<Clock>(RCL_STEADY_TIME), period, std::move(callback), context)
|
||||
std::make_shared<Clock>(RCL_STEADY_TIME), period, std::move(callback), context, autostart)
|
||||
{}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="2">
|
||||
<name>rclcpp</name>
|
||||
<version>21.2.0</version>
|
||||
<version>22.1.0</version>
|
||||
<description>The ROS client library in C++.</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -431,6 +431,22 @@ void Executor::spin_some(std::chrono::nanoseconds max_duration)
|
||||
return this->spin_some_impl(max_duration, false);
|
||||
}
|
||||
|
||||
void
|
||||
Executor::spin_node_all(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
|
||||
std::chrono::nanoseconds max_duration)
|
||||
{
|
||||
this->add_node(node, false);
|
||||
spin_all(max_duration);
|
||||
this->remove_node(node, false);
|
||||
}
|
||||
|
||||
void
|
||||
Executor::spin_node_all(std::shared_ptr<rclcpp::Node> node, std::chrono::nanoseconds max_duration)
|
||||
{
|
||||
this->spin_node_all(node->get_node_base_interface(), max_duration);
|
||||
}
|
||||
|
||||
void Executor::spin_all(std::chrono::nanoseconds max_duration)
|
||||
{
|
||||
if (max_duration < 0ns) {
|
||||
|
||||
@@ -14,6 +14,21 @@
|
||||
|
||||
#include "rclcpp/executors.hpp"
|
||||
|
||||
void
|
||||
rclcpp::spin_all(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
|
||||
std::chrono::nanoseconds max_duration)
|
||||
{
|
||||
rclcpp::executors::SingleThreadedExecutor exec;
|
||||
exec.spin_node_all(node_ptr, max_duration);
|
||||
}
|
||||
|
||||
void
|
||||
rclcpp::spin_all(rclcpp::Node::SharedPtr node_ptr, std::chrono::nanoseconds max_duration)
|
||||
{
|
||||
rclcpp::spin_all(node_ptr->get_node_base_interface(), max_duration);
|
||||
}
|
||||
|
||||
void
|
||||
rclcpp::spin_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr)
|
||||
{
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "rclcpp/node_interfaces/node_time_source.hpp"
|
||||
#include "rclcpp/node_interfaces/node_timers.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics.hpp"
|
||||
#include "rclcpp/node_interfaces/node_type_descriptions.hpp"
|
||||
#include "rclcpp/node_interfaces/node_waitables.hpp"
|
||||
#include "rclcpp/qos_overriding_options.hpp"
|
||||
|
||||
@@ -109,6 +110,22 @@ create_effective_namespace(const std::string & node_namespace, const std::string
|
||||
|
||||
} // namespace
|
||||
|
||||
/// Internal implementation to provide hidden and API/ABI stable changes to the Node.
|
||||
/**
|
||||
* This class is intended to be an "escape hatch" within a stable distribution, so that certain
|
||||
* smaller features and bugfixes can be backported, having a place to put new members, while
|
||||
* maintaining the ABI.
|
||||
*
|
||||
* This is not intended to be a parking place for new features, it should be used for backports
|
||||
* only, left empty and unallocated in Rolling.
|
||||
*/
|
||||
class Node::NodeImpl
|
||||
{
|
||||
public:
|
||||
NodeImpl() = default;
|
||||
~NodeImpl() = default;
|
||||
};
|
||||
|
||||
Node::Node(
|
||||
const std::string & node_name,
|
||||
const NodeOptions & options)
|
||||
@@ -206,6 +223,12 @@ Node::Node(
|
||||
options.clock_qos(),
|
||||
options.use_clock_thread()
|
||||
)),
|
||||
node_type_descriptions_(new rclcpp::node_interfaces::NodeTypeDescriptions(
|
||||
node_base_,
|
||||
node_logging_,
|
||||
node_parameters_,
|
||||
node_services_
|
||||
)),
|
||||
node_waitables_(new rclcpp::node_interfaces::NodeWaitables(node_base_.get())),
|
||||
node_options_(options),
|
||||
sub_namespace_(""),
|
||||
@@ -246,7 +269,8 @@ Node::Node(
|
||||
node_waitables_(other.node_waitables_),
|
||||
node_options_(other.node_options_),
|
||||
sub_namespace_(extend_sub_namespace(other.get_sub_namespace(), sub_namespace)),
|
||||
effective_namespace_(create_effective_namespace(other.get_namespace(), sub_namespace_))
|
||||
effective_namespace_(create_effective_namespace(other.get_namespace(), sub_namespace_)),
|
||||
hidden_impl_(other.hidden_impl_)
|
||||
{
|
||||
// Validate new effective namespace.
|
||||
int validation_result;
|
||||
@@ -591,6 +615,12 @@ Node::get_node_topics_interface()
|
||||
return node_topics_;
|
||||
}
|
||||
|
||||
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr
|
||||
Node::get_node_type_descriptions_interface()
|
||||
{
|
||||
return node_type_descriptions_;
|
||||
}
|
||||
|
||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr
|
||||
Node::get_node_services_interface()
|
||||
{
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "rclcpp/node_interfaces/node_base.hpp"
|
||||
|
||||
#include "rcl/arguments.h"
|
||||
#include "rcl/node_type_cache.h"
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rcutils/logging_macros.h"
|
||||
#include "rmw/validate_namespace.h"
|
||||
|
||||
@@ -32,8 +32,7 @@ NodeServices::add_service(
|
||||
{
|
||||
if (group) {
|
||||
if (!node_base_->callback_group_in_node(group)) {
|
||||
// TODO(jacquelinekay): use custom exception
|
||||
throw std::runtime_error("Cannot create service, group not in node.");
|
||||
throw rclcpp::exceptions::MissingGroupNodeException("service");
|
||||
}
|
||||
} else {
|
||||
group = node_base_->get_default_callback_group();
|
||||
@@ -58,8 +57,7 @@ NodeServices::add_client(
|
||||
{
|
||||
if (group) {
|
||||
if (!node_base_->callback_group_in_node(group)) {
|
||||
// TODO(jacquelinekay): use custom exception
|
||||
throw std::runtime_error("Cannot create client, group not in node.");
|
||||
throw rclcpp::exceptions::MissingGroupNodeException("client");
|
||||
}
|
||||
} else {
|
||||
group = node_base_->get_default_callback_group();
|
||||
|
||||
@@ -34,8 +34,7 @@ NodeTimers::add_timer(
|
||||
{
|
||||
if (callback_group) {
|
||||
if (!node_base_->callback_group_in_node(callback_group)) {
|
||||
// TODO(jacquelinekay): use custom exception
|
||||
throw std::runtime_error("Cannot create timer, group not in node.");
|
||||
throw rclcpp::exceptions::MissingGroupNodeException("timer");
|
||||
}
|
||||
} else {
|
||||
callback_group = node_base_->get_default_callback_group();
|
||||
|
||||
@@ -58,7 +58,7 @@ NodeTopics::add_publisher(
|
||||
// Assign to a group.
|
||||
if (callback_group) {
|
||||
if (!node_base_->callback_group_in_node(callback_group)) {
|
||||
throw std::runtime_error("Cannot create publisher, callback group not in node.");
|
||||
throw rclcpp::exceptions::MissingGroupNodeException("publisher");
|
||||
}
|
||||
} else {
|
||||
callback_group = node_base_->get_default_callback_group();
|
||||
@@ -97,8 +97,7 @@ NodeTopics::add_subscription(
|
||||
// Assign to a group.
|
||||
if (callback_group) {
|
||||
if (!node_base_->callback_group_in_node(callback_group)) {
|
||||
// TODO(jacquelinekay): use custom exception
|
||||
throw std::runtime_error("Cannot create subscription, callback group not in node.");
|
||||
throw rclcpp::exceptions::MissingGroupNodeException("subscription");
|
||||
}
|
||||
} else {
|
||||
callback_group = node_base_->get_default_callback_group();
|
||||
|
||||
157
rclcpp/src/rclcpp/node_interfaces/node_type_descriptions.cpp
Normal file
157
rclcpp/src/rclcpp/node_interfaces/node_type_descriptions.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "rclcpp/node_interfaces/node_type_descriptions.hpp"
|
||||
#include "rclcpp/parameter_client.hpp"
|
||||
|
||||
#include "type_description_interfaces/srv/get_type_description.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
// Helper wrapper for rclcpp::Service to access ::Request and ::Response types for allocation.
|
||||
struct GetTypeDescription__C
|
||||
{
|
||||
using Request = type_description_interfaces__srv__GetTypeDescription_Request;
|
||||
using Response = type_description_interfaces__srv__GetTypeDescription_Response;
|
||||
using Event = type_description_interfaces__srv__GetTypeDescription_Event;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// Helper function for C typesupport.
|
||||
namespace rosidl_typesupport_cpp
|
||||
{
|
||||
template<>
|
||||
rosidl_service_type_support_t const *
|
||||
get_service_type_support_handle<GetTypeDescription__C>()
|
||||
{
|
||||
return ROSIDL_GET_SRV_TYPE_SUPPORT(type_description_interfaces, srv, GetTypeDescription);
|
||||
}
|
||||
} // namespace rosidl_typesupport_cpp
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
class NodeTypeDescriptions::NodeTypeDescriptionsImpl
|
||||
{
|
||||
public:
|
||||
using ServiceT = GetTypeDescription__C;
|
||||
|
||||
rclcpp::Logger logger_;
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_;
|
||||
rclcpp::Service<ServiceT>::SharedPtr type_description_srv_;
|
||||
|
||||
NodeTypeDescriptionsImpl(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
|
||||
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters,
|
||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services)
|
||||
: logger_(node_logging->get_logger()),
|
||||
node_base_(node_base)
|
||||
{
|
||||
const std::string enable_param_name = "start_type_description_service";
|
||||
|
||||
bool enabled = false;
|
||||
try {
|
||||
auto enable_param = node_parameters->declare_parameter(
|
||||
enable_param_name,
|
||||
rclcpp::ParameterValue(true),
|
||||
rcl_interfaces::msg::ParameterDescriptor()
|
||||
.set__name(enable_param_name)
|
||||
.set__type(rclcpp::PARAMETER_BOOL)
|
||||
.set__description("Start the ~/get_type_description service for this node.")
|
||||
.set__read_only(true));
|
||||
enabled = enable_param.get<bool>();
|
||||
} catch (const rclcpp::exceptions::InvalidParameterTypeException & exc) {
|
||||
RCLCPP_ERROR(logger_, "%s", exc.what());
|
||||
throw;
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
auto rcl_node = node_base->get_rcl_node_handle();
|
||||
rcl_ret_t rcl_ret = rcl_node_type_description_service_init(rcl_node);
|
||||
if (rcl_ret != RCL_RET_OK) {
|
||||
RCLCPP_ERROR(
|
||||
logger_, "Failed to initialize ~/get_type_description_service: %s",
|
||||
rcl_get_error_string().str);
|
||||
throw std::runtime_error(
|
||||
"Failed to initialize ~/get_type_description service.");
|
||||
}
|
||||
|
||||
rcl_service_t * rcl_srv = nullptr;
|
||||
rcl_ret = rcl_node_get_type_description_service(rcl_node, &rcl_srv);
|
||||
if (rcl_ret != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
"Failed to get initialized ~/get_type_description service from rcl.");
|
||||
}
|
||||
|
||||
rclcpp::AnyServiceCallback<ServiceT> cb;
|
||||
cb.set(
|
||||
[this](
|
||||
std::shared_ptr<rmw_request_id_t> header,
|
||||
std::shared_ptr<ServiceT::Request> request,
|
||||
std::shared_ptr<ServiceT::Response> response
|
||||
) {
|
||||
rcl_node_type_description_service_handle_request(
|
||||
node_base_->get_rcl_node_handle(),
|
||||
header.get(),
|
||||
request.get(),
|
||||
response.get());
|
||||
});
|
||||
|
||||
type_description_srv_ = std::make_shared<Service<ServiceT>>(
|
||||
node_base_->get_shared_rcl_node_handle(),
|
||||
rcl_srv,
|
||||
cb);
|
||||
node_services->add_service(
|
||||
std::dynamic_pointer_cast<ServiceBase>(type_description_srv_),
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
~NodeTypeDescriptionsImpl()
|
||||
{
|
||||
if (
|
||||
type_description_srv_ &&
|
||||
RCL_RET_OK != rcl_node_type_description_service_fini(node_base_->get_rcl_node_handle()))
|
||||
{
|
||||
RCLCPP_ERROR(
|
||||
logger_,
|
||||
"Error in shutdown of get_type_description service: %s", rcl_get_error_string().str);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
NodeTypeDescriptions::NodeTypeDescriptions(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
|
||||
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters,
|
||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services)
|
||||
: impl_(new NodeTypeDescriptionsImpl(
|
||||
node_base,
|
||||
node_logging,
|
||||
node_parameters,
|
||||
node_services))
|
||||
{}
|
||||
|
||||
NodeTypeDescriptions::~NodeTypeDescriptions()
|
||||
{}
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
@@ -32,8 +32,7 @@ NodeWaitables::add_waitable(
|
||||
{
|
||||
if (group) {
|
||||
if (!node_base_->callback_group_in_node(group)) {
|
||||
// TODO(jacobperron): use custom exception
|
||||
throw std::runtime_error("Cannot create waitable, group not in node.");
|
||||
throw rclcpp::exceptions::MissingGroupNodeException("waitable");
|
||||
}
|
||||
} else {
|
||||
group = node_base_->get_default_callback_group();
|
||||
|
||||
@@ -129,8 +129,7 @@ ParameterValue::ParameterValue(const rcl_interfaces::msg::ParameterValue & value
|
||||
case PARAMETER_NOT_SET:
|
||||
break;
|
||||
default:
|
||||
// TODO(wjwwood): use custom exception
|
||||
throw std::runtime_error("Unknown type: " + std::to_string(value.type));
|
||||
throw rclcpp::exceptions::UnknownTypeError(std::to_string(value.type));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -54,9 +55,7 @@ public:
|
||||
ros_time_active_ = true;
|
||||
|
||||
// Update all attached clocks to zero or last recorded time
|
||||
for (auto it = associated_clocks_.begin(); it != associated_clocks_.end(); ++it) {
|
||||
set_clock(last_time_msg_, true, *it);
|
||||
}
|
||||
set_all_clocks(last_time_msg_, true);
|
||||
}
|
||||
|
||||
// An internal method to use in the clock callback that iterates and disables all clocks
|
||||
@@ -71,11 +70,8 @@ public:
|
||||
ros_time_active_ = false;
|
||||
|
||||
// Update all attached clocks
|
||||
std::lock_guard<std::mutex> guard(clock_list_lock_);
|
||||
for (auto it = associated_clocks_.begin(); it != associated_clocks_.end(); ++it) {
|
||||
auto msg = std::make_shared<builtin_interfaces::msg::Time>();
|
||||
set_clock(msg, false, *it);
|
||||
}
|
||||
auto msg = std::make_shared<builtin_interfaces::msg::Time>();
|
||||
set_all_clocks(msg, false);
|
||||
}
|
||||
|
||||
// Check if ROS time is active
|
||||
@@ -95,7 +91,7 @@ public:
|
||||
}
|
||||
}
|
||||
std::lock_guard<std::mutex> guard(clock_list_lock_);
|
||||
associated_clocks_.push_back(clock);
|
||||
associated_clocks_.insert(clock);
|
||||
// Set the clock to zero unless there's a recently received message
|
||||
set_clock(last_time_msg_, ros_time_active_, clock);
|
||||
}
|
||||
@@ -104,10 +100,8 @@ public:
|
||||
void detachClock(rclcpp::Clock::SharedPtr clock)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(clock_list_lock_);
|
||||
auto result = std::find(associated_clocks_.begin(), associated_clocks_.end(), clock);
|
||||
if (result != associated_clocks_.end()) {
|
||||
associated_clocks_.erase(result);
|
||||
} else {
|
||||
auto removed = associated_clocks_.erase(clock);
|
||||
if (removed == 0) {
|
||||
RCLCPP_ERROR(logger_, "failed to remove clock");
|
||||
}
|
||||
}
|
||||
@@ -184,8 +178,8 @@ private:
|
||||
|
||||
// A lock to protect iterating the associated_clocks_ field.
|
||||
std::mutex clock_list_lock_;
|
||||
// A vector to store references to associated clocks.
|
||||
std::vector<rclcpp::Clock::SharedPtr> associated_clocks_;
|
||||
// An unordered_set to store references to associated clocks.
|
||||
std::unordered_set<rclcpp::Clock::SharedPtr> associated_clocks_;
|
||||
|
||||
// Local storage of validity of ROS time
|
||||
// This is needed when new clocks are added.
|
||||
|
||||
@@ -32,7 +32,8 @@ using rclcpp::TimerBase;
|
||||
TimerBase::TimerBase(
|
||||
rclcpp::Clock::SharedPtr clock,
|
||||
std::chrono::nanoseconds period,
|
||||
rclcpp::Context::SharedPtr context)
|
||||
rclcpp::Context::SharedPtr context,
|
||||
bool autostart)
|
||||
: clock_(clock), timer_handle_(nullptr)
|
||||
{
|
||||
if (nullptr == context) {
|
||||
@@ -64,9 +65,9 @@ TimerBase::TimerBase(
|
||||
rcl_clock_t * clock_handle = clock_->get_clock_handle();
|
||||
{
|
||||
std::lock_guard<std::mutex> clock_guard(clock_->get_clock_mutex());
|
||||
rcl_ret_t ret = rcl_timer_init(
|
||||
timer_handle_.get(), clock_handle, rcl_context.get(), period.count(), nullptr,
|
||||
rcl_get_default_allocator());
|
||||
rcl_ret_t ret = rcl_timer_init2(
|
||||
timer_handle_.get(), clock_handle, rcl_context.get(), period.count(),
|
||||
nullptr, rcl_get_default_allocator(), autostart);
|
||||
if (ret != RCL_RET_OK) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret, "Couldn't initialize rcl timer handle");
|
||||
}
|
||||
|
||||
@@ -262,6 +262,11 @@ if(TARGET test_node_interfaces__node_topics)
|
||||
"test_msgs")
|
||||
target_link_libraries(test_node_interfaces__node_topics ${PROJECT_NAME} mimick)
|
||||
endif()
|
||||
ament_add_gtest(test_node_interfaces__node_type_descriptions
|
||||
node_interfaces/test_node_type_descriptions.cpp)
|
||||
if(TARGET test_node_interfaces__node_type_descriptions)
|
||||
target_link_libraries(test_node_interfaces__node_type_descriptions ${PROJECT_NAME} mimick)
|
||||
endif()
|
||||
ament_add_gtest(test_node_interfaces__node_waitables
|
||||
node_interfaces/test_node_waitables.cpp)
|
||||
if(TARGET test_node_interfaces__node_waitables)
|
||||
|
||||
@@ -43,11 +43,6 @@ public:
|
||||
|
||||
TEST_F(TestEventsExecutor, run_pub_sub)
|
||||
{
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("node");
|
||||
|
||||
bool msg_received = false;
|
||||
@@ -80,8 +75,6 @@ TEST_F(TestEventsExecutor, run_pub_sub)
|
||||
!spin_exited &&
|
||||
(std::chrono::high_resolution_clock::now() - start < 1s))
|
||||
{
|
||||
auto time = std::chrono::high_resolution_clock::now() - start;
|
||||
auto time_msec = std::chrono::duration_cast<std::chrono::milliseconds>(time);
|
||||
std::this_thread::sleep_for(25ms);
|
||||
}
|
||||
|
||||
@@ -95,11 +88,6 @@ TEST_F(TestEventsExecutor, run_pub_sub)
|
||||
|
||||
TEST_F(TestEventsExecutor, run_clients_servers)
|
||||
{
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("node");
|
||||
|
||||
bool request_received = false;
|
||||
@@ -153,11 +141,6 @@ TEST_F(TestEventsExecutor, run_clients_servers)
|
||||
|
||||
TEST_F(TestEventsExecutor, spin_once_max_duration_timeout)
|
||||
{
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("node");
|
||||
|
||||
EventsExecutor executor;
|
||||
@@ -190,11 +173,6 @@ TEST_F(TestEventsExecutor, spin_once_max_duration_timeout)
|
||||
|
||||
TEST_F(TestEventsExecutor, spin_once_max_duration_timer)
|
||||
{
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("node");
|
||||
|
||||
EventsExecutor executor;
|
||||
@@ -226,11 +204,6 @@ TEST_F(TestEventsExecutor, spin_once_max_duration_timer)
|
||||
|
||||
TEST_F(TestEventsExecutor, spin_some_max_duration)
|
||||
{
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("node");
|
||||
|
||||
@@ -277,11 +250,6 @@ TEST_F(TestEventsExecutor, spin_some_max_duration)
|
||||
|
||||
TEST_F(TestEventsExecutor, spin_some_zero_duration)
|
||||
{
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("node");
|
||||
|
||||
size_t t_runs = 0;
|
||||
@@ -303,11 +271,6 @@ TEST_F(TestEventsExecutor, spin_some_zero_duration)
|
||||
|
||||
TEST_F(TestEventsExecutor, spin_all_max_duration)
|
||||
{
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("node");
|
||||
|
||||
@@ -358,11 +321,6 @@ TEST_F(TestEventsExecutor, spin_all_max_duration)
|
||||
|
||||
TEST_F(TestEventsExecutor, cancel_while_timers_running)
|
||||
{
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("node");
|
||||
|
||||
EventsExecutor executor;
|
||||
@@ -402,11 +360,6 @@ TEST_F(TestEventsExecutor, cancel_while_timers_running)
|
||||
|
||||
TEST_F(TestEventsExecutor, cancel_while_timers_waiting)
|
||||
{
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("node");
|
||||
|
||||
size_t t1_runs = 0;
|
||||
@@ -435,11 +388,6 @@ TEST_F(TestEventsExecutor, destroy_entities)
|
||||
// This test fails on Windows! We skip it for now
|
||||
GTEST_SKIP();
|
||||
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
// Create a publisher node and start publishing messages
|
||||
auto node_pub = std::make_shared<rclcpp::Node>("node_pub");
|
||||
auto publisher = node_pub->create_publisher<test_msgs::msg::Empty>("topic", rclcpp::QoS(10));
|
||||
@@ -485,11 +433,6 @@ std::string * g_sub_log_msg;
|
||||
std::promise<void> * g_log_msgs_promise;
|
||||
TEST_F(TestEventsExecutor, test_default_incompatible_qos_callbacks)
|
||||
{
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("node");
|
||||
rcutils_logging_output_handler_t original_output_handler = rcutils_logging_get_output_handler();
|
||||
|
||||
|
||||
@@ -135,14 +135,6 @@ TYPED_TEST_SUITE(TestExecutorsStable, StandardExecutors, ExecutorTypeNames);
|
||||
TYPED_TEST(TestExecutors, detachOnDestruction)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
{
|
||||
ExecutorType executor;
|
||||
executor.add_node(this->node);
|
||||
@@ -159,14 +151,6 @@ TYPED_TEST(TestExecutors, detachOnDestruction)
|
||||
TYPED_TEST(TestExecutorsStable, addTemporaryNode)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor;
|
||||
|
||||
{
|
||||
@@ -187,14 +171,6 @@ TYPED_TEST(TestExecutorsStable, addTemporaryNode)
|
||||
TYPED_TEST(TestExecutors, emptyExecutor)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor;
|
||||
std::thread spinner([&]() {EXPECT_NO_THROW(executor.spin());});
|
||||
std::this_thread::sleep_for(50ms);
|
||||
@@ -206,14 +182,6 @@ TYPED_TEST(TestExecutors, emptyExecutor)
|
||||
TYPED_TEST(TestExecutors, addNodeTwoExecutors)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor1;
|
||||
ExecutorType executor2;
|
||||
EXPECT_NO_THROW(executor1.add_node(this->node));
|
||||
@@ -225,14 +193,6 @@ TYPED_TEST(TestExecutors, addNodeTwoExecutors)
|
||||
TYPED_TEST(TestExecutors, spinWithTimer)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor;
|
||||
|
||||
bool timer_completed = false;
|
||||
@@ -256,14 +216,6 @@ TYPED_TEST(TestExecutors, spinWithTimer)
|
||||
TYPED_TEST(TestExecutors, spinWhileAlreadySpinning)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor;
|
||||
executor.add_node(this->node);
|
||||
|
||||
@@ -291,14 +243,6 @@ TYPED_TEST(TestExecutors, spinWhileAlreadySpinning)
|
||||
TYPED_TEST(TestExecutors, testSpinUntilFutureComplete)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor;
|
||||
executor.add_node(this->node);
|
||||
|
||||
@@ -322,14 +266,6 @@ TYPED_TEST(TestExecutors, testSpinUntilFutureComplete)
|
||||
TYPED_TEST(TestExecutors, testSpinUntilSharedFutureComplete)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor;
|
||||
executor.add_node(this->node);
|
||||
|
||||
@@ -354,14 +290,6 @@ TYPED_TEST(TestExecutors, testSpinUntilSharedFutureComplete)
|
||||
TYPED_TEST(TestExecutors, testSpinUntilFutureCompleteNoTimeout)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor;
|
||||
executor.add_node(this->node);
|
||||
|
||||
@@ -409,14 +337,6 @@ TYPED_TEST(TestExecutors, testSpinUntilFutureCompleteNoTimeout)
|
||||
TYPED_TEST(TestExecutors, testSpinUntilFutureCompleteWithTimeout)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor;
|
||||
executor.add_node(this->node);
|
||||
|
||||
@@ -529,14 +449,6 @@ private:
|
||||
TYPED_TEST(TestExecutors, spinAll)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor;
|
||||
auto waitable_interfaces = this->node->get_node_waitables_interface();
|
||||
auto my_waitable = std::make_shared<TestWaitable>();
|
||||
@@ -579,14 +491,6 @@ TYPED_TEST(TestExecutors, spinAll)
|
||||
TYPED_TEST(TestExecutors, spinSome)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor;
|
||||
auto waitable_interfaces = this->node->get_node_waitables_interface();
|
||||
auto my_waitable = std::make_shared<TestWaitable>();
|
||||
@@ -629,14 +533,6 @@ TYPED_TEST(TestExecutors, spinSome)
|
||||
TYPED_TEST(TestExecutors, testSpinNodeUntilFutureCompleteNodeBasePtr)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor;
|
||||
|
||||
std::promise<bool> promise;
|
||||
@@ -653,14 +549,6 @@ TYPED_TEST(TestExecutors, testSpinNodeUntilFutureCompleteNodeBasePtr)
|
||||
TYPED_TEST(TestExecutors, testSpinNodeUntilFutureCompleteNodePtr)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor;
|
||||
|
||||
std::promise<bool> promise;
|
||||
@@ -677,14 +565,6 @@ TYPED_TEST(TestExecutors, testSpinNodeUntilFutureCompleteNodePtr)
|
||||
TYPED_TEST(TestExecutors, testSpinUntilFutureCompleteInterrupted)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor;
|
||||
executor.add_node(this->node);
|
||||
|
||||
@@ -858,7 +738,7 @@ public:
|
||||
test_name << test_info->test_case_name() << "_" << test_info->name();
|
||||
node = std::make_shared<rclcpp::Node>("node", test_name.str());
|
||||
|
||||
callback_count = 0;
|
||||
callback_count = 0u;
|
||||
|
||||
const std::string topic_name = std::string("topic_") + test_name.str();
|
||||
|
||||
@@ -867,7 +747,7 @@ public:
|
||||
publisher = node->create_publisher<test_msgs::msg::Empty>(topic_name, rclcpp::QoS(1), po);
|
||||
|
||||
auto callback = [this](test_msgs::msg::Empty::ConstSharedPtr) {
|
||||
this->callback_count.fetch_add(1);
|
||||
this->callback_count.fetch_add(1u);
|
||||
};
|
||||
|
||||
rclcpp::SubscriptionOptions so;
|
||||
@@ -889,7 +769,7 @@ public:
|
||||
rclcpp::Node::SharedPtr node;
|
||||
rclcpp::Publisher<test_msgs::msg::Empty>::SharedPtr publisher;
|
||||
rclcpp::Subscription<test_msgs::msg::Empty>::SharedPtr subscription;
|
||||
std::atomic_int callback_count;
|
||||
std::atomic_size_t callback_count;
|
||||
};
|
||||
|
||||
TYPED_TEST_SUITE(TestIntraprocessExecutors, ExecutorTypes, ExecutorTypeNames);
|
||||
@@ -905,7 +785,7 @@ TYPED_TEST(TestIntraprocessExecutors, testIntraprocessRetrigger) {
|
||||
ExecutorType executor;
|
||||
executor.add_node(this->node);
|
||||
|
||||
EXPECT_EQ(0, this->callback_count.load());
|
||||
EXPECT_EQ(0u, this->callback_count.load());
|
||||
this->publisher->publish(test_msgs::msg::Empty());
|
||||
|
||||
// Wait for up to 5 seconds for the first message to come available.
|
||||
@@ -919,7 +799,7 @@ TYPED_TEST(TestIntraprocessExecutors, testIntraprocessRetrigger) {
|
||||
EXPECT_EQ(1u, this->callback_count.load());
|
||||
|
||||
// reset counter
|
||||
this->callback_count.store(0);
|
||||
this->callback_count.store(0u);
|
||||
|
||||
for (size_t ii = 0; ii < kNumMessages; ++ii) {
|
||||
this->publisher->publish(test_msgs::msg::Empty());
|
||||
|
||||
@@ -77,9 +77,9 @@ TEST_F(TestNodeParameters, list_parameters)
|
||||
std::vector<std::string> prefixes;
|
||||
const auto list_result = node_parameters->list_parameters(prefixes, 1u);
|
||||
|
||||
// Currently the only default parameter is 'use_sim_time', but that may change.
|
||||
// Currently the default parameters are 'use_sim_time' and 'start_type_description_service'
|
||||
size_t number_of_parameters = list_result.names.size();
|
||||
EXPECT_GE(1u, number_of_parameters);
|
||||
EXPECT_GE(2u, number_of_parameters);
|
||||
|
||||
const std::string parameter_name = "new_parameter";
|
||||
const rclcpp::ParameterValue value(true);
|
||||
|
||||
@@ -92,7 +92,7 @@ TEST_F(TestNodeService, add_service)
|
||||
different_node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
node_services->add_service(service, callback_group_in_different_node),
|
||||
std::runtime_error("Cannot create service, group not in node."));
|
||||
rclcpp::exceptions::MissingGroupNodeException("service"));
|
||||
}
|
||||
|
||||
TEST_F(TestNodeService, add_service_rcl_trigger_guard_condition_error)
|
||||
@@ -119,7 +119,7 @@ TEST_F(TestNodeService, add_client)
|
||||
different_node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
node_services->add_client(client, callback_group_in_different_node),
|
||||
std::runtime_error("Cannot create client, group not in node."));
|
||||
rclcpp::exceptions::MissingGroupNodeException("client"));
|
||||
}
|
||||
|
||||
TEST_F(TestNodeService, add_client_rcl_trigger_guard_condition_error)
|
||||
|
||||
@@ -75,7 +75,7 @@ TEST_F(TestNodeTimers, add_timer)
|
||||
different_node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
node_timers->add_timer(timer, callback_group_in_different_node),
|
||||
std::runtime_error("Cannot create timer, group not in node."));
|
||||
rclcpp::exceptions::MissingGroupNodeException("timer"));
|
||||
}
|
||||
|
||||
TEST_F(TestNodeTimers, add_timer_rcl_trigger_guard_condition_error)
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/node_interfaces/node_type_descriptions.hpp"
|
||||
|
||||
class TestNodeTypeDescriptions : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
void SetUp()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
{
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TestNodeTypeDescriptions, interface_created)
|
||||
{
|
||||
rclcpp::Node node{"node", "ns"};
|
||||
ASSERT_NE(nullptr, node.get_node_type_descriptions_interface());
|
||||
}
|
||||
|
||||
TEST_F(TestNodeTypeDescriptions, disabled_no_service)
|
||||
{
|
||||
rclcpp::NodeOptions node_options;
|
||||
node_options.append_parameter_override("start_type_description_service", false);
|
||||
rclcpp::Node node{"node", "ns", node_options};
|
||||
|
||||
rcl_node_t * rcl_node = node.get_node_base_interface()->get_rcl_node_handle();
|
||||
rcl_service_t * srv = nullptr;
|
||||
rcl_ret_t ret = rcl_node_get_type_description_service(rcl_node, &srv);
|
||||
ASSERT_EQ(RCL_RET_NOT_INIT, ret);
|
||||
}
|
||||
|
||||
TEST_F(TestNodeTypeDescriptions, enabled_creates_service)
|
||||
{
|
||||
rclcpp::NodeOptions node_options;
|
||||
node_options.append_parameter_override("start_type_description_service", true);
|
||||
rclcpp::Node node{"node", "ns", node_options};
|
||||
|
||||
rcl_node_t * rcl_node = node.get_node_base_interface()->get_rcl_node_handle();
|
||||
rcl_service_t * srv = nullptr;
|
||||
rcl_ret_t ret = rcl_node_get_type_description_service(rcl_node, &srv);
|
||||
ASSERT_EQ(RCL_RET_OK, ret);
|
||||
ASSERT_NE(nullptr, srv);
|
||||
}
|
||||
@@ -78,7 +78,7 @@ TEST_F(TestNodeWaitables, add_remove_waitable)
|
||||
node_waitables->add_waitable(waitable, callback_group1));
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
node_waitables->add_waitable(waitable, callback_group2),
|
||||
std::runtime_error("Cannot create waitable, group not in node."));
|
||||
rclcpp::exceptions::MissingGroupNodeException("waitable"));
|
||||
EXPECT_NO_THROW(node_waitables->remove_waitable(waitable, callback_group1));
|
||||
EXPECT_NO_THROW(node_waitables->remove_waitable(waitable, callback_group2));
|
||||
|
||||
|
||||
@@ -99,13 +99,6 @@ TYPED_TEST_SUITE(TestAddCallbackGroupsToExecutorStable, StandardExecutors, Execu
|
||||
TYPED_TEST(TestAddCallbackGroupsToExecutor, add_callback_groups)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
auto timer_callback = []() {};
|
||||
@@ -155,13 +148,6 @@ TYPED_TEST(TestAddCallbackGroupsToExecutor, add_callback_groups)
|
||||
TYPED_TEST(TestAddCallbackGroupsToExecutor, remove_callback_groups)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
auto timer_callback = []() {};
|
||||
@@ -193,13 +179,6 @@ TYPED_TEST(TestAddCallbackGroupsToExecutor, remove_callback_groups)
|
||||
TYPED_TEST(TestAddCallbackGroupsToExecutor, add_duplicate_callback_groups)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor;
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
@@ -220,13 +199,6 @@ TYPED_TEST(TestAddCallbackGroupsToExecutor, add_duplicate_callback_groups)
|
||||
TYPED_TEST(TestAddCallbackGroupsToExecutor, add_callback_groups_after_add_node_to_executor)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor;
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
@@ -263,13 +235,6 @@ TYPED_TEST(TestAddCallbackGroupsToExecutor, add_callback_groups_after_add_node_t
|
||||
TYPED_TEST(TestAddCallbackGroupsToExecutor, add_unallowable_callback_groups)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor;
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
@@ -307,13 +272,6 @@ TYPED_TEST(TestAddCallbackGroupsToExecutor, add_unallowable_callback_groups)
|
||||
TYPED_TEST(TestAddCallbackGroupsToExecutor, one_node_many_callback_groups_many_executors)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType timer_executor;
|
||||
ExecutorType sub_executor;
|
||||
@@ -355,13 +313,6 @@ TYPED_TEST(TestAddCallbackGroupsToExecutor, one_node_many_callback_groups_many_e
|
||||
TYPED_TEST(TestAddCallbackGroupsToExecutorStable, subscriber_triggered_to_receive_message)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
|
||||
@@ -428,13 +379,6 @@ TYPED_TEST(TestAddCallbackGroupsToExecutorStable, subscriber_triggered_to_receiv
|
||||
TYPED_TEST(TestAddCallbackGroupsToExecutorStable, callback_group_create_after_spin)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
|
||||
@@ -481,13 +425,6 @@ TYPED_TEST(TestAddCallbackGroupsToExecutorStable, callback_group_create_after_sp
|
||||
TYPED_TEST(TestAddCallbackGroupsToExecutor, remove_callback_group)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
// rmw_connextdds doesn't support events-executor
|
||||
if (
|
||||
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
|
||||
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
|
||||
{
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
ExecutorType executor;
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
|
||||
@@ -193,3 +193,29 @@ TEST(TestCreateTimer, timer_function_pointer)
|
||||
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
TEST(TestCreateTimer, timer_without_autostart)
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
auto node = std::make_shared<rclcpp::Node>("test_create_timer_node");
|
||||
|
||||
rclcpp::TimerBase::SharedPtr timer;
|
||||
timer = rclcpp::create_timer(
|
||||
node,
|
||||
node->get_clock(),
|
||||
rclcpp::Duration(0ms),
|
||||
[]() {},
|
||||
nullptr,
|
||||
false);
|
||||
|
||||
EXPECT_TRUE(timer->is_canceled());
|
||||
EXPECT_EQ(timer->time_until_trigger().count(), std::chrono::nanoseconds::max().count());
|
||||
|
||||
timer->reset();
|
||||
EXPECT_LE(timer->time_until_trigger().count(), std::chrono::nanoseconds::max().count());
|
||||
EXPECT_FALSE(timer->is_canceled());
|
||||
|
||||
timer->cancel();
|
||||
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
@@ -546,6 +546,40 @@ TEST_F(TestExecutor, spin_node_once_node) {
|
||||
EXPECT_TRUE(spin_called);
|
||||
}
|
||||
|
||||
TEST_F(TestExecutor, spin_node_all_base_interface) {
|
||||
DummyExecutor dummy;
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
bool spin_called = false;
|
||||
auto timer =
|
||||
node->create_wall_timer(
|
||||
std::chrono::milliseconds(1), [&]() {
|
||||
spin_called = true;
|
||||
});
|
||||
|
||||
// Wait for the wall timer to have expired.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
EXPECT_FALSE(spin_called);
|
||||
dummy.spin_node_all(node->get_node_base_interface(), std::chrono::milliseconds(50));
|
||||
EXPECT_TRUE(spin_called);
|
||||
}
|
||||
|
||||
TEST_F(TestExecutor, spin_node_all_node) {
|
||||
DummyExecutor dummy;
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
bool spin_called = false;
|
||||
auto timer =
|
||||
node->create_wall_timer(
|
||||
std::chrono::milliseconds(1), [&]() {
|
||||
spin_called = true;
|
||||
});
|
||||
|
||||
// Wait for the wall timer to have expired.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
EXPECT_FALSE(spin_called);
|
||||
dummy.spin_node_all(node, std::chrono::milliseconds(50));
|
||||
EXPECT_TRUE(spin_called);
|
||||
}
|
||||
|
||||
TEST_F(TestExecutor, spin_until_future_complete_future_already_complete) {
|
||||
DummyExecutor dummy;
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
|
||||
@@ -78,6 +78,7 @@ TEST_F(TestNode, construction_and_destruction) {
|
||||
EXPECT_NE(nullptr, node->get_node_options().get_rcl_node_options());
|
||||
EXPECT_NE(nullptr, node->get_graph_event());
|
||||
EXPECT_NE(nullptr, node->get_clock());
|
||||
EXPECT_NE(nullptr, node->get_node_type_descriptions_interface());
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -59,6 +59,8 @@ protected:
|
||||
node_with_option.reset();
|
||||
}
|
||||
|
||||
// "start_type_description_service" and "use_sim_time"
|
||||
const uint64_t builtin_param_count = 2;
|
||||
rclcpp::Node::SharedPtr node;
|
||||
rclcpp::Node::SharedPtr node_with_option;
|
||||
};
|
||||
@@ -925,6 +927,7 @@ TEST_F(TestParameterClient, sync_parameter_delete_parameters) {
|
||||
Coverage for async load_parameters
|
||||
*/
|
||||
TEST_F(TestParameterClient, async_parameter_load_parameters) {
|
||||
const uint64_t expected_param_count = 4 + builtin_param_count;
|
||||
auto load_node = std::make_shared<rclcpp::Node>(
|
||||
"load_node",
|
||||
"namespace",
|
||||
@@ -944,12 +947,13 @@ TEST_F(TestParameterClient, async_parameter_load_parameters) {
|
||||
auto list_parameters = asynchronous_client->list_parameters({}, 3);
|
||||
rclcpp::spin_until_future_complete(
|
||||
load_node, list_parameters, std::chrono::milliseconds(100));
|
||||
ASSERT_EQ(list_parameters.get().names.size(), static_cast<uint64_t>(5));
|
||||
ASSERT_EQ(list_parameters.get().names.size(), expected_param_count);
|
||||
}
|
||||
/*
|
||||
Coverage for sync load_parameters
|
||||
*/
|
||||
TEST_F(TestParameterClient, sync_parameter_load_parameters) {
|
||||
const uint64_t expected_param_count = 4 + builtin_param_count;
|
||||
auto load_node = std::make_shared<rclcpp::Node>(
|
||||
"load_node",
|
||||
"namespace",
|
||||
@@ -964,13 +968,14 @@ TEST_F(TestParameterClient, sync_parameter_load_parameters) {
|
||||
ASSERT_EQ(load_future[0].successful, true);
|
||||
// list parameters
|
||||
auto list_parameters = synchronous_client->list_parameters({}, 3);
|
||||
ASSERT_EQ(list_parameters.names.size(), static_cast<uint64_t>(5));
|
||||
ASSERT_EQ(list_parameters.names.size(), static_cast<uint64_t>(expected_param_count));
|
||||
}
|
||||
|
||||
/*
|
||||
Coverage for async load_parameters with complicated regex expression
|
||||
*/
|
||||
TEST_F(TestParameterClient, async_parameter_load_parameters_complicated_regex) {
|
||||
const uint64_t expected_param_count = 5 + builtin_param_count;
|
||||
auto load_node = std::make_shared<rclcpp::Node>(
|
||||
"load_node",
|
||||
"namespace",
|
||||
@@ -990,7 +995,7 @@ TEST_F(TestParameterClient, async_parameter_load_parameters_complicated_regex) {
|
||||
auto list_parameters = asynchronous_client->list_parameters({}, 3);
|
||||
rclcpp::spin_until_future_complete(
|
||||
load_node, list_parameters, std::chrono::milliseconds(100));
|
||||
ASSERT_EQ(list_parameters.get().names.size(), static_cast<uint64_t>(6));
|
||||
ASSERT_EQ(list_parameters.get().names.size(), expected_param_count);
|
||||
// to check the parameter "a_value"
|
||||
std::string param_name = "a_value";
|
||||
auto param = load_node->get_parameter(param_name);
|
||||
@@ -1020,6 +1025,7 @@ TEST_F(TestParameterClient, async_parameter_load_no_valid_parameter) {
|
||||
Coverage for async load_parameters from maps with complicated regex expression
|
||||
*/
|
||||
TEST_F(TestParameterClient, async_parameter_load_parameters_from_map) {
|
||||
const uint64_t expected_param_count = 5 + builtin_param_count;
|
||||
auto load_node = std::make_shared<rclcpp::Node>(
|
||||
"load_node",
|
||||
"namespace",
|
||||
@@ -1068,7 +1074,7 @@ TEST_F(TestParameterClient, async_parameter_load_parameters_from_map) {
|
||||
auto list_parameters = asynchronous_client->list_parameters({}, 3);
|
||||
rclcpp::spin_until_future_complete(
|
||||
load_node, list_parameters, std::chrono::milliseconds(100));
|
||||
ASSERT_EQ(list_parameters.get().names.size(), static_cast<uint64_t>(6));
|
||||
ASSERT_EQ(list_parameters.get().names.size(), expected_param_count);
|
||||
// to check the parameter "a_value"
|
||||
std::string param_name = "a_value";
|
||||
auto param = load_node->get_parameter(param_name);
|
||||
|
||||
@@ -314,11 +314,6 @@ TEST_F(TestQosEvent, add_to_wait_set) {
|
||||
|
||||
TEST_F(TestQosEvent, test_on_new_event_callback)
|
||||
{
|
||||
// rmw_connextdds doesn't support rmw_event_set_callback() interface
|
||||
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
auto offered_deadline = rclcpp::Duration(std::chrono::milliseconds(1));
|
||||
auto requested_deadline = rclcpp::Duration(std::chrono::milliseconds(2));
|
||||
|
||||
@@ -360,11 +355,6 @@ TEST_F(TestQosEvent, test_on_new_event_callback)
|
||||
|
||||
TEST_F(TestQosEvent, test_invalid_on_new_event_callback)
|
||||
{
|
||||
// rmw_connextdds doesn't support rmw_event_set_callback() interface
|
||||
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
auto pub = node->create_publisher<test_msgs::msg::Empty>(topic_name, 10);
|
||||
auto sub = node->create_subscription<test_msgs::msg::Empty>(topic_name, 10, message_callback);
|
||||
auto dummy_cb = [](size_t count_events) {(void)count_events;};
|
||||
@@ -439,11 +429,6 @@ TEST_F(TestQosEvent, test_invalid_on_new_event_callback)
|
||||
|
||||
TEST_F(TestQosEvent, test_pub_matched_event_by_set_event_callback)
|
||||
{
|
||||
// rmw_connextdds doesn't support rmw_event_set_callback() interface
|
||||
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
std::atomic_size_t matched_count = 0;
|
||||
|
||||
rclcpp::PublisherOptions pub_options;
|
||||
@@ -451,8 +436,10 @@ TEST_F(TestQosEvent, test_pub_matched_event_by_set_event_callback)
|
||||
auto pub = node->create_publisher<test_msgs::msg::Empty>(
|
||||
topic_name, 10, pub_options);
|
||||
|
||||
auto matched_event_callback = [&matched_count](size_t count) {
|
||||
std::promise<void> prom;
|
||||
auto matched_event_callback = [&matched_count, &prom](size_t count) {
|
||||
matched_count += count;
|
||||
prom.set_value();
|
||||
};
|
||||
|
||||
pub->set_on_new_qos_event_callback(matched_event_callback, RCL_PUBLISHER_MATCHED);
|
||||
@@ -460,34 +447,32 @@ TEST_F(TestQosEvent, test_pub_matched_event_by_set_event_callback)
|
||||
rclcpp::executors::SingleThreadedExecutor ex;
|
||||
ex.add_node(node->get_node_base_interface());
|
||||
|
||||
const auto timeout = std::chrono::milliseconds(200);
|
||||
const auto timeout = std::chrono::seconds(10);
|
||||
|
||||
{
|
||||
auto sub1 = node->create_subscription<test_msgs::msg::Empty>(topic_name, 10, message_callback);
|
||||
ex.spin_some(timeout);
|
||||
ex.spin_until_future_complete(prom.get_future(), timeout);
|
||||
prom = {};
|
||||
EXPECT_EQ(matched_count, static_cast<size_t>(1));
|
||||
|
||||
{
|
||||
auto sub2 = node->create_subscription<test_msgs::msg::Empty>(
|
||||
topic_name, 10, message_callback);
|
||||
ex.spin_some(timeout);
|
||||
ex.spin_until_future_complete(prom.get_future(), timeout);
|
||||
prom = {};
|
||||
EXPECT_EQ(matched_count, static_cast<size_t>(2));
|
||||
}
|
||||
ex.spin_some(timeout);
|
||||
ex.spin_until_future_complete(prom.get_future(), timeout);
|
||||
prom = {};
|
||||
EXPECT_EQ(matched_count, static_cast<size_t>(3));
|
||||
}
|
||||
|
||||
ex.spin_some(timeout);
|
||||
ex.spin_until_future_complete(prom.get_future(), timeout);
|
||||
EXPECT_EQ(matched_count, static_cast<size_t>(4));
|
||||
}
|
||||
|
||||
TEST_F(TestQosEvent, test_sub_matched_event_by_set_event_callback)
|
||||
{
|
||||
// rmw_connextdds doesn't support rmw_event_set_callback() interface
|
||||
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
|
||||
GTEST_SKIP();
|
||||
}
|
||||
|
||||
std::atomic_size_t matched_count = 0;
|
||||
|
||||
rclcpp::SubscriptionOptions sub_options;
|
||||
@@ -495,8 +480,10 @@ TEST_F(TestQosEvent, test_sub_matched_event_by_set_event_callback)
|
||||
auto sub = node->create_subscription<test_msgs::msg::Empty>(
|
||||
topic_name, 10, message_callback, sub_options);
|
||||
|
||||
auto matched_event_callback = [&matched_count](size_t count) {
|
||||
std::promise<void> prom;
|
||||
auto matched_event_callback = [&matched_count, &prom](size_t count) {
|
||||
matched_count += count;
|
||||
prom.set_value();
|
||||
};
|
||||
|
||||
sub->set_on_new_qos_event_callback(matched_event_callback, RCL_SUBSCRIPTION_MATCHED);
|
||||
@@ -504,39 +491,44 @@ TEST_F(TestQosEvent, test_sub_matched_event_by_set_event_callback)
|
||||
rclcpp::executors::SingleThreadedExecutor ex;
|
||||
ex.add_node(node->get_node_base_interface());
|
||||
|
||||
const auto timeout = std::chrono::milliseconds(200);
|
||||
const auto timeout = std::chrono::seconds(10000);
|
||||
|
||||
{
|
||||
auto pub1 = node->create_publisher<test_msgs::msg::Empty>(topic_name, 10);
|
||||
|
||||
ex.spin_some(timeout);
|
||||
ex.spin_until_future_complete(prom.get_future(), timeout);
|
||||
prom = {};
|
||||
EXPECT_EQ(matched_count, static_cast<size_t>(1));
|
||||
|
||||
{
|
||||
auto pub2 = node->create_publisher<test_msgs::msg::Empty>(topic_name, 10);
|
||||
ex.spin_some(timeout);
|
||||
ex.spin_until_future_complete(prom.get_future(), timeout);
|
||||
prom = {};
|
||||
EXPECT_EQ(matched_count, static_cast<size_t>(2));
|
||||
}
|
||||
|
||||
ex.spin_some(timeout);
|
||||
ex.spin_until_future_complete(prom.get_future(), timeout);
|
||||
prom = {};
|
||||
EXPECT_EQ(matched_count, static_cast<size_t>(3));
|
||||
}
|
||||
|
||||
ex.spin_some(timeout);
|
||||
ex.spin_until_future_complete(prom.get_future(), timeout);
|
||||
EXPECT_EQ(matched_count, static_cast<size_t>(4));
|
||||
}
|
||||
|
||||
TEST_F(TestQosEvent, test_pub_matched_event_by_option_event_callback)
|
||||
{
|
||||
rmw_matched_status_t matched_expected_result;
|
||||
std::promise<void> prom;
|
||||
|
||||
rclcpp::PublisherOptions pub_options;
|
||||
pub_options.event_callbacks.matched_callback =
|
||||
[&matched_expected_result](rmw_matched_status_t & s) {
|
||||
[&matched_expected_result, &prom](rmw_matched_status_t & s) {
|
||||
EXPECT_EQ(s.total_count, matched_expected_result.total_count);
|
||||
EXPECT_EQ(s.total_count_change, matched_expected_result.total_count_change);
|
||||
EXPECT_EQ(s.current_count, matched_expected_result.current_count);
|
||||
EXPECT_EQ(s.current_count_change, matched_expected_result.current_count_change);
|
||||
prom.set_value();
|
||||
};
|
||||
|
||||
auto pub = node->create_publisher<test_msgs::msg::Empty>(
|
||||
@@ -551,11 +543,12 @@ TEST_F(TestQosEvent, test_pub_matched_event_by_option_event_callback)
|
||||
matched_expected_result.current_count = 1;
|
||||
matched_expected_result.current_count_change = 1;
|
||||
|
||||
const auto timeout = std::chrono::milliseconds(200);
|
||||
const auto timeout = std::chrono::seconds(10);
|
||||
|
||||
{
|
||||
auto sub = node->create_subscription<test_msgs::msg::Empty>(topic_name, 10, message_callback);
|
||||
ex.spin_some(timeout);
|
||||
ex.spin_until_future_complete(prom.get_future(), timeout);
|
||||
prom = {};
|
||||
|
||||
// destroy a connected subscription
|
||||
matched_expected_result.total_count = 1;
|
||||
@@ -563,20 +556,22 @@ TEST_F(TestQosEvent, test_pub_matched_event_by_option_event_callback)
|
||||
matched_expected_result.current_count = 0;
|
||||
matched_expected_result.current_count_change = -1;
|
||||
}
|
||||
ex.spin_some(timeout);
|
||||
ex.spin_until_future_complete(prom.get_future(), timeout);
|
||||
}
|
||||
|
||||
TEST_F(TestQosEvent, test_sub_matched_event_by_option_event_callback)
|
||||
{
|
||||
rmw_matched_status_t matched_expected_result;
|
||||
|
||||
std::promise<void> prom;
|
||||
rclcpp::SubscriptionOptions sub_options;
|
||||
sub_options.event_callbacks.matched_callback =
|
||||
[&matched_expected_result](rmw_matched_status_t & s) {
|
||||
[&matched_expected_result, &prom](rmw_matched_status_t & s) {
|
||||
EXPECT_EQ(s.total_count, matched_expected_result.total_count);
|
||||
EXPECT_EQ(s.total_count_change, matched_expected_result.total_count_change);
|
||||
EXPECT_EQ(s.current_count, matched_expected_result.current_count);
|
||||
EXPECT_EQ(s.current_count_change, matched_expected_result.current_count_change);
|
||||
prom.set_value();
|
||||
};
|
||||
auto sub = node->create_subscription<test_msgs::msg::Empty>(
|
||||
topic_name, 10, message_callback, sub_options);
|
||||
@@ -590,10 +585,11 @@ TEST_F(TestQosEvent, test_sub_matched_event_by_option_event_callback)
|
||||
matched_expected_result.current_count = 1;
|
||||
matched_expected_result.current_count_change = 1;
|
||||
|
||||
const auto timeout = std::chrono::milliseconds(200);
|
||||
const auto timeout = std::chrono::seconds(10);
|
||||
{
|
||||
auto pub1 = node->create_publisher<test_msgs::msg::Empty>(topic_name, 10);
|
||||
ex.spin_some(timeout);
|
||||
ex.spin_until_future_complete(prom.get_future(), timeout);
|
||||
prom = {};
|
||||
|
||||
// destroy a connected publisher
|
||||
matched_expected_result.total_count = 1;
|
||||
@@ -601,5 +597,5 @@ TEST_F(TestQosEvent, test_sub_matched_event_by_option_event_callback)
|
||||
matched_expected_result.current_count = 0;
|
||||
matched_expected_result.current_count_change = -1;
|
||||
}
|
||||
ex.spin_some(timeout);
|
||||
ex.spin_until_future_complete(prom.get_future(), timeout);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
@@ -34,114 +36,28 @@ using namespace std::chrono_literals;
|
||||
class TestSubscription : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
void OnMessage(test_msgs::msg::Empty::ConstSharedPtr msg)
|
||||
void on_message(test_msgs::msg::Empty::ConstSharedPtr msg)
|
||||
{
|
||||
(void)msg;
|
||||
}
|
||||
|
||||
protected:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
|
||||
protected:
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
void initialize(const rclcpp::NodeOptions & node_options = rclcpp::NodeOptions())
|
||||
{
|
||||
node = std::make_shared<rclcpp::Node>("test_subscription", "/ns", node_options);
|
||||
node_ = std::make_shared<rclcpp::Node>("test_subscription", "/ns", node_options);
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
{
|
||||
node.reset();
|
||||
}
|
||||
|
||||
rclcpp::Node::SharedPtr node;
|
||||
};
|
||||
|
||||
struct TestParameters
|
||||
{
|
||||
TestParameters(rclcpp::QoS qos, std::string description)
|
||||
: qos(qos), description(description) {}
|
||||
rclcpp::QoS qos;
|
||||
std::string description;
|
||||
};
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, const TestParameters & params)
|
||||
{
|
||||
out << params.description;
|
||||
return out;
|
||||
}
|
||||
|
||||
class TestSubscriptionInvalidIntraprocessQos
|
||||
: public TestSubscription,
|
||||
public ::testing::WithParamInterface<TestParameters>
|
||||
{};
|
||||
|
||||
class TestSubscriptionSub : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
void OnMessage(test_msgs::msg::Empty::ConstSharedPtr msg)
|
||||
{
|
||||
(void)msg;
|
||||
}
|
||||
|
||||
protected:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
}
|
||||
|
||||
void SetUp()
|
||||
{
|
||||
node = std::make_shared<rclcpp::Node>("test_subscription", "/ns");
|
||||
subnode = node->create_sub_node("sub_ns");
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
{
|
||||
node.reset();
|
||||
}
|
||||
|
||||
rclcpp::Node::SharedPtr node;
|
||||
rclcpp::Node::SharedPtr subnode;
|
||||
};
|
||||
|
||||
class SubscriptionClassNodeInheritance : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
SubscriptionClassNodeInheritance()
|
||||
: Node("subscription_class_node_inheritance")
|
||||
{
|
||||
}
|
||||
|
||||
void OnMessage(test_msgs::msg::Empty::ConstSharedPtr msg)
|
||||
{
|
||||
(void)msg;
|
||||
}
|
||||
|
||||
void CreateSubscription()
|
||||
{
|
||||
auto callback = std::bind(
|
||||
&SubscriptionClassNodeInheritance::OnMessage, this, std::placeholders::_1);
|
||||
using test_msgs::msg::Empty;
|
||||
auto sub = this->create_subscription<Empty>("topic", 10, callback);
|
||||
}
|
||||
};
|
||||
|
||||
class SubscriptionClass
|
||||
{
|
||||
public:
|
||||
void OnMessage(test_msgs::msg::Empty::ConstSharedPtr msg)
|
||||
{
|
||||
(void)msg;
|
||||
}
|
||||
|
||||
void CreateSubscription()
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("test_subscription_member_callback", "/ns");
|
||||
auto callback = std::bind(&SubscriptionClass::OnMessage, this, std::placeholders::_1);
|
||||
using test_msgs::msg::Empty;
|
||||
auto sub = node->create_subscription<Empty>("topic", 10, callback);
|
||||
}
|
||||
rclcpp::Node::SharedPtr node_;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -155,7 +71,7 @@ TEST_F(TestSubscription, construction_and_destruction) {
|
||||
};
|
||||
{
|
||||
constexpr size_t depth = 10u;
|
||||
auto sub = node->create_subscription<Empty>("topic", depth, callback);
|
||||
auto sub = node_->create_subscription<Empty>("topic", depth, callback);
|
||||
|
||||
EXPECT_NE(nullptr, sub->get_subscription_handle());
|
||||
// Converting to base class was necessary for the compiler to choose the const version of
|
||||
@@ -172,40 +88,7 @@ TEST_F(TestSubscription, construction_and_destruction) {
|
||||
{
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto sub = node->create_subscription<Empty>("invalid_topic?", 10, callback);
|
||||
}, rclcpp::exceptions::InvalidTopicNameError);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Testing subscription construction and destruction for subnodes.
|
||||
*/
|
||||
TEST_F(TestSubscriptionSub, construction_and_destruction) {
|
||||
using test_msgs::msg::Empty;
|
||||
auto callback = [](Empty::ConstSharedPtr msg) {
|
||||
(void)msg;
|
||||
};
|
||||
{
|
||||
auto sub = subnode->create_subscription<Empty>("topic", 1, callback);
|
||||
EXPECT_STREQ(sub->get_topic_name(), "/ns/sub_ns/topic");
|
||||
}
|
||||
|
||||
{
|
||||
auto sub = subnode->create_subscription<Empty>("/topic", 1, callback);
|
||||
EXPECT_STREQ(sub->get_topic_name(), "/topic");
|
||||
}
|
||||
|
||||
{
|
||||
auto sub = subnode->create_subscription<Empty>("~/topic", 1, callback);
|
||||
std::string expected_topic_name =
|
||||
std::string(node->get_namespace()) + "/" + node->get_name() + "/topic";
|
||||
EXPECT_STREQ(sub->get_topic_name(), expected_topic_name.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto sub = node->create_subscription<Empty>("invalid_topic?", 1, callback);
|
||||
auto sub = node_->create_subscription<Empty>("invalid_topic?", 10, callback);
|
||||
}, rclcpp::exceptions::InvalidTopicNameError);
|
||||
}
|
||||
}
|
||||
@@ -218,31 +101,31 @@ TEST_F(TestSubscription, various_creation_signatures) {
|
||||
using test_msgs::msg::Empty;
|
||||
auto cb = [](test_msgs::msg::Empty::ConstSharedPtr) {};
|
||||
{
|
||||
auto sub = node->create_subscription<Empty>("topic", 1, cb);
|
||||
auto sub = node_->create_subscription<Empty>("topic", 1, cb);
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub = node->create_subscription<Empty>("topic", rclcpp::QoS(1), cb);
|
||||
auto sub = node_->create_subscription<Empty>("topic", rclcpp::QoS(1), cb);
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub =
|
||||
node->create_subscription<Empty>("topic", rclcpp::QoS(rclcpp::KeepLast(1)), cb);
|
||||
node_->create_subscription<Empty>("topic", rclcpp::QoS(rclcpp::KeepLast(1)), cb);
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub =
|
||||
node->create_subscription<Empty>("topic", rclcpp::QoS(rclcpp::KeepAll()), cb);
|
||||
node_->create_subscription<Empty>("topic", rclcpp::QoS(rclcpp::KeepAll()), cb);
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub = node->create_subscription<Empty>(
|
||||
auto sub = node_->create_subscription<Empty>(
|
||||
"topic", 42, cb, rclcpp::SubscriptionOptions());
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub = rclcpp::create_subscription<Empty>(
|
||||
node, "topic", 42, cb, rclcpp::SubscriptionOptions());
|
||||
node_, "topic", 42, cb, rclcpp::SubscriptionOptions());
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
@@ -250,40 +133,78 @@ TEST_F(TestSubscription, various_creation_signatures) {
|
||||
options.allocator = std::make_shared<std::allocator<void>>();
|
||||
EXPECT_NE(nullptr, options.get_allocator());
|
||||
auto sub = rclcpp::create_subscription<Empty>(
|
||||
node, "topic", 42, cb, options);
|
||||
node_, "topic", 42, cb, options);
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
rclcpp::SubscriptionOptionsBase options_base;
|
||||
rclcpp::SubscriptionOptionsWithAllocator<std::allocator<void>> options(options_base);
|
||||
auto sub = rclcpp::create_subscription<Empty>(
|
||||
node, "topic", 42, cb, options);
|
||||
node_, "topic", 42, cb, options);
|
||||
(void)sub;
|
||||
}
|
||||
}
|
||||
|
||||
class SubscriptionClass final
|
||||
{
|
||||
public:
|
||||
void custom_create_subscription()
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("test_subscription_member_callback", "/ns");
|
||||
auto callback = std::bind(&SubscriptionClass::on_message, this, std::placeholders::_1);
|
||||
auto sub = node->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
|
||||
}
|
||||
|
||||
private:
|
||||
void on_message(test_msgs::msg::Empty::ConstSharedPtr msg)
|
||||
{
|
||||
(void)msg;
|
||||
}
|
||||
};
|
||||
|
||||
class SubscriptionClassNodeInheritance final : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
SubscriptionClassNodeInheritance()
|
||||
: Node("subscription_class_node_inheritance")
|
||||
{
|
||||
}
|
||||
|
||||
void custom_create_subscription()
|
||||
{
|
||||
auto callback = std::bind(
|
||||
&SubscriptionClassNodeInheritance::on_message, this, std::placeholders::_1);
|
||||
auto sub = this->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
|
||||
}
|
||||
|
||||
private:
|
||||
void on_message(test_msgs::msg::Empty::ConstSharedPtr msg)
|
||||
{
|
||||
(void)msg;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Testing subscriptions using std::bind.
|
||||
*/
|
||||
TEST_F(TestSubscription, callback_bind) {
|
||||
initialize();
|
||||
using test_msgs::msg::Empty;
|
||||
{
|
||||
// Member callback for plain class
|
||||
SubscriptionClass subscription_object;
|
||||
subscription_object.CreateSubscription();
|
||||
subscription_object.custom_create_subscription();
|
||||
}
|
||||
{
|
||||
// Member callback for class inheriting from rclcpp::Node
|
||||
SubscriptionClassNodeInheritance subscription_object;
|
||||
subscription_object.CreateSubscription();
|
||||
subscription_object.custom_create_subscription();
|
||||
}
|
||||
{
|
||||
// Member callback for class inheriting from testing::Test
|
||||
// Regression test for https://github.com/ros2/rclcpp/issues/479 where the TEST_F GTest macro
|
||||
// was interfering with rclcpp's `function_traits`.
|
||||
auto callback = std::bind(&TestSubscription::OnMessage, this, std::placeholders::_1);
|
||||
auto sub = node->create_subscription<Empty>("topic", 1, callback);
|
||||
auto callback = std::bind(&TestSubscription::on_message, this, std::placeholders::_1);
|
||||
auto sub = node_->create_subscription<test_msgs::msg::Empty>("topic", 1, callback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,10 +213,9 @@ TEST_F(TestSubscription, callback_bind) {
|
||||
*/
|
||||
TEST_F(TestSubscription, take) {
|
||||
initialize();
|
||||
using test_msgs::msg::Empty;
|
||||
auto do_nothing = [](std::shared_ptr<const test_msgs::msg::Empty>) {FAIL();};
|
||||
{
|
||||
auto sub = node->create_subscription<test_msgs::msg::Empty>("~/test_take", 1, do_nothing);
|
||||
auto sub = node_->create_subscription<test_msgs::msg::Empty>("~/test_take", 1, do_nothing);
|
||||
test_msgs::msg::Empty msg;
|
||||
rclcpp::MessageInfo msg_info;
|
||||
EXPECT_FALSE(sub->take(msg, msg_info));
|
||||
@@ -303,23 +223,23 @@ TEST_F(TestSubscription, take) {
|
||||
{
|
||||
rclcpp::SubscriptionOptions so;
|
||||
so.use_intra_process_comm = rclcpp::IntraProcessSetting::Disable;
|
||||
auto sub = node->create_subscription<test_msgs::msg::Empty>("~/test_take", 1, do_nothing, so);
|
||||
auto sub = node_->create_subscription<test_msgs::msg::Empty>("~/test_take", 1, do_nothing, so);
|
||||
rclcpp::PublisherOptions po;
|
||||
po.use_intra_process_comm = rclcpp::IntraProcessSetting::Disable;
|
||||
auto pub = node->create_publisher<test_msgs::msg::Empty>("~/test_take", 1, po);
|
||||
auto pub = node_->create_publisher<test_msgs::msg::Empty>("~/test_take", 1, po);
|
||||
{
|
||||
test_msgs::msg::Empty msg;
|
||||
pub->publish(msg);
|
||||
}
|
||||
test_msgs::msg::Empty msg;
|
||||
rclcpp::MessageInfo msg_info;
|
||||
bool message_recieved = false;
|
||||
bool message_received = false;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
do {
|
||||
message_recieved = sub->take(msg, msg_info);
|
||||
message_received = sub->take(msg, msg_info);
|
||||
std::this_thread::sleep_for(100ms);
|
||||
} while (!message_recieved && std::chrono::steady_clock::now() - start < 10s);
|
||||
EXPECT_TRUE(message_recieved);
|
||||
} while (!message_received && std::chrono::steady_clock::now() - start < 10s);
|
||||
EXPECT_TRUE(message_received);
|
||||
}
|
||||
// TODO(wjwwood): figure out a good way to test the intra-process exclusion behavior.
|
||||
}
|
||||
@@ -329,10 +249,9 @@ TEST_F(TestSubscription, take) {
|
||||
*/
|
||||
TEST_F(TestSubscription, take_serialized) {
|
||||
initialize();
|
||||
using test_msgs::msg::Empty;
|
||||
auto do_nothing = [](std::shared_ptr<const rclcpp::SerializedMessage>) {FAIL();};
|
||||
{
|
||||
auto sub = node->create_subscription<test_msgs::msg::Empty>("~/test_take", 1, do_nothing);
|
||||
auto sub = node_->create_subscription<test_msgs::msg::Empty>("~/test_take", 1, do_nothing);
|
||||
std::shared_ptr<rclcpp::SerializedMessage> msg = sub->create_serialized_message();
|
||||
rclcpp::MessageInfo msg_info;
|
||||
EXPECT_FALSE(sub->take_serialized(*msg, msg_info));
|
||||
@@ -340,23 +259,23 @@ TEST_F(TestSubscription, take_serialized) {
|
||||
{
|
||||
rclcpp::SubscriptionOptions so;
|
||||
so.use_intra_process_comm = rclcpp::IntraProcessSetting::Disable;
|
||||
auto sub = node->create_subscription<test_msgs::msg::Empty>("~/test_take", 1, do_nothing, so);
|
||||
auto sub = node_->create_subscription<test_msgs::msg::Empty>("~/test_take", 1, do_nothing, so);
|
||||
rclcpp::PublisherOptions po;
|
||||
po.use_intra_process_comm = rclcpp::IntraProcessSetting::Disable;
|
||||
auto pub = node->create_publisher<test_msgs::msg::Empty>("~/test_take", 1, po);
|
||||
auto pub = node_->create_publisher<test_msgs::msg::Empty>("~/test_take", 1, po);
|
||||
{
|
||||
test_msgs::msg::Empty msg;
|
||||
pub->publish(msg);
|
||||
}
|
||||
std::shared_ptr<rclcpp::SerializedMessage> msg = sub->create_serialized_message();
|
||||
rclcpp::MessageInfo msg_info;
|
||||
bool message_recieved = false;
|
||||
bool message_received = false;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
do {
|
||||
message_recieved = sub->take_serialized(*msg, msg_info);
|
||||
message_received = sub->take_serialized(*msg, msg_info);
|
||||
std::this_thread::sleep_for(100ms);
|
||||
} while (!message_recieved && std::chrono::steady_clock::now() - start < 10s);
|
||||
EXPECT_TRUE(message_recieved);
|
||||
} while (!message_received && std::chrono::steady_clock::now() - start < 10s);
|
||||
EXPECT_TRUE(message_received);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,7 +287,7 @@ TEST_F(TestSubscription, rcl_subscription_init_error) {
|
||||
|
||||
// reset() is not needed for triggering exception, just to avoid an unused return value warning
|
||||
EXPECT_THROW(
|
||||
node->create_subscription<test_msgs::msg::Empty>("topic", 10, callback).reset(),
|
||||
node_->create_subscription<test_msgs::msg::Empty>("topic", 10, callback).reset(),
|
||||
rclcpp::exceptions::RCLError);
|
||||
}
|
||||
|
||||
@@ -380,7 +299,7 @@ TEST_F(TestSubscription, rcl_subscription_fini_error) {
|
||||
|
||||
// Cleanup just fails, no exception expected
|
||||
EXPECT_NO_THROW(
|
||||
node->create_subscription<test_msgs::msg::Empty>("topic", 10, callback).reset());
|
||||
node_->create_subscription<test_msgs::msg::Empty>("topic", 10, callback).reset());
|
||||
}
|
||||
|
||||
TEST_F(TestSubscription, rcl_subscription_get_actual_qos_error) {
|
||||
@@ -389,7 +308,7 @@ TEST_F(TestSubscription, rcl_subscription_get_actual_qos_error) {
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rclcpp", rcl_subscription_get_actual_qos, nullptr);
|
||||
|
||||
auto sub = node->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
|
||||
auto sub = node_->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
sub->get_actual_qos(), std::runtime_error("failed to get qos settings: error not set"));
|
||||
}
|
||||
@@ -400,7 +319,7 @@ TEST_F(TestSubscription, rcl_take_type_erased_error) {
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rclcpp", rcl_take, RCL_RET_ERROR);
|
||||
|
||||
auto sub = node->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
|
||||
auto sub = node_->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
|
||||
test_msgs::msg::Empty msg;
|
||||
rclcpp::MessageInfo message_info;
|
||||
|
||||
@@ -413,7 +332,7 @@ TEST_F(TestSubscription, rcl_take_serialized_message_error) {
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rclcpp", rcl_take_serialized_message, RCL_RET_ERROR);
|
||||
|
||||
auto sub = node->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
|
||||
auto sub = node_->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
|
||||
rclcpp::SerializedMessage msg;
|
||||
rclcpp::MessageInfo message_info;
|
||||
|
||||
@@ -426,14 +345,14 @@ TEST_F(TestSubscription, rcl_subscription_get_publisher_count_error) {
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rclcpp", rcl_subscription_get_publisher_count, RCL_RET_ERROR);
|
||||
|
||||
auto sub = node->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
|
||||
auto sub = node_->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
|
||||
EXPECT_THROW(sub->get_publisher_count(), rclcpp::exceptions::RCLError);
|
||||
}
|
||||
|
||||
TEST_F(TestSubscription, handle_loaned_message) {
|
||||
initialize();
|
||||
auto callback = [](std::shared_ptr<const test_msgs::msg::Empty>) {};
|
||||
auto sub = node->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
|
||||
auto sub = node_->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
|
||||
|
||||
test_msgs::msg::Empty msg;
|
||||
rclcpp::MessageInfo message_info;
|
||||
@@ -448,13 +367,13 @@ TEST_F(TestSubscription, on_new_message_callback) {
|
||||
using test_msgs::msg::Empty;
|
||||
|
||||
auto do_nothing = [](std::shared_ptr<const test_msgs::msg::Empty>) {FAIL();};
|
||||
auto sub = node->create_subscription<test_msgs::msg::Empty>("~/test_take", 10, do_nothing);
|
||||
auto sub = node_->create_subscription<test_msgs::msg::Empty>("~/test_take", 10, do_nothing);
|
||||
|
||||
std::atomic<size_t> c1 {0};
|
||||
auto increase_c1_cb = [&c1](size_t count_msgs) {c1 += count_msgs;};
|
||||
sub->set_on_new_message_callback(increase_c1_cb);
|
||||
|
||||
auto pub = node->create_publisher<test_msgs::msg::Empty>("~/test_take", 3);
|
||||
auto pub = node_->create_publisher<test_msgs::msg::Empty>("~/test_take", 3);
|
||||
{
|
||||
test_msgs::msg::Empty msg;
|
||||
pub->publish(msg);
|
||||
@@ -518,13 +437,13 @@ TEST_F(TestSubscription, on_new_intra_process_message_callback) {
|
||||
using test_msgs::msg::Empty;
|
||||
|
||||
auto do_nothing = [](std::shared_ptr<const test_msgs::msg::Empty>) {FAIL();};
|
||||
auto sub = node->create_subscription<test_msgs::msg::Empty>("~/test_take", 10, do_nothing);
|
||||
auto sub = node_->create_subscription<test_msgs::msg::Empty>("~/test_take", 10, do_nothing);
|
||||
|
||||
std::atomic<size_t> c1 {0};
|
||||
auto increase_c1_cb = [&c1](size_t count_msgs) {c1 += count_msgs;};
|
||||
sub->set_on_new_intra_process_message_callback(increase_c1_cb);
|
||||
|
||||
auto pub = node->create_publisher<test_msgs::msg::Empty>("~/test_take", 1);
|
||||
auto pub = node_->create_publisher<test_msgs::msg::Empty>("~/test_take", 1);
|
||||
{
|
||||
test_msgs::msg::Empty msg;
|
||||
pub->publish(msg);
|
||||
@@ -580,80 +499,13 @@ TEST_F(TestSubscription, on_new_intra_process_message_callback) {
|
||||
EXPECT_THROW(sub->set_on_new_intra_process_message_callback(invalid_cb), std::invalid_argument);
|
||||
}
|
||||
|
||||
/*
|
||||
Testing subscription with intraprocess enabled and invalid QoS
|
||||
*/
|
||||
TEST_P(TestSubscriptionInvalidIntraprocessQos, test_subscription_throws) {
|
||||
initialize(rclcpp::NodeOptions().use_intra_process_comms(true));
|
||||
rclcpp::QoS qos = GetParam().qos;
|
||||
using test_msgs::msg::Empty;
|
||||
{
|
||||
auto callback = std::bind(
|
||||
&TestSubscriptionInvalidIntraprocessQos::OnMessage,
|
||||
this,
|
||||
std::placeholders::_1);
|
||||
|
||||
ASSERT_THROW(
|
||||
{auto subscription = node->create_subscription<Empty>(
|
||||
"topic",
|
||||
qos,
|
||||
callback);},
|
||||
std::invalid_argument);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Testing subscription with invalid use_intra_process_comm
|
||||
*/
|
||||
TEST_P(TestSubscriptionInvalidIntraprocessQos, test_subscription_throws_intraprocess) {
|
||||
rclcpp::SubscriptionOptionsWithAllocator<std::allocator<void>> options;
|
||||
options.use_intra_process_comm = static_cast<rclcpp::IntraProcessSetting>(5);
|
||||
|
||||
initialize();
|
||||
rclcpp::QoS qos = GetParam().qos;
|
||||
auto callback = std::bind(
|
||||
&TestSubscriptionInvalidIntraprocessQos::OnMessage,
|
||||
this,
|
||||
std::placeholders::_1);
|
||||
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
{auto subscription = node->create_subscription<test_msgs::msg::Empty>(
|
||||
"topic",
|
||||
qos,
|
||||
callback,
|
||||
options);},
|
||||
std::runtime_error("Unrecognized IntraProcessSetting value"));
|
||||
}
|
||||
|
||||
static std::vector<TestParameters> invalid_qos_profiles()
|
||||
{
|
||||
std::vector<TestParameters> parameters;
|
||||
|
||||
parameters.reserve(3);
|
||||
parameters.push_back(
|
||||
TestParameters(
|
||||
rclcpp::QoS(rclcpp::KeepLast(10)).transient_local(),
|
||||
"transient_local_qos"));
|
||||
parameters.push_back(
|
||||
TestParameters(
|
||||
rclcpp::QoS(rclcpp::KeepAll()),
|
||||
"keep_all_qos"));
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
TestSubscriptionThrows, TestSubscriptionInvalidIntraprocessQos,
|
||||
::testing::ValuesIn(invalid_qos_profiles()),
|
||||
::testing::PrintToStringParamName());
|
||||
|
||||
TEST_F(TestSubscription, get_network_flow_endpoints_errors) {
|
||||
initialize();
|
||||
const rclcpp::QoS subscription_qos(1);
|
||||
auto subscription_callback = [](test_msgs::msg::Empty::ConstSharedPtr msg) {
|
||||
(void)msg;
|
||||
};
|
||||
auto subscription = node->create_subscription<test_msgs::msg::Empty>(
|
||||
auto subscription = node_->create_subscription<test_msgs::msg::Empty>(
|
||||
"topic", subscription_qos, subscription_callback);
|
||||
|
||||
{
|
||||
@@ -680,3 +532,143 @@ TEST_F(TestSubscription, get_network_flow_endpoints_errors) {
|
||||
EXPECT_NO_THROW(subscription->get_network_flow_endpoints());
|
||||
}
|
||||
}
|
||||
|
||||
class TestSubscriptionSub : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
void SetUp()
|
||||
{
|
||||
node_ = std::make_shared<rclcpp::Node>("test_subscription", "/ns");
|
||||
subnode_ = node_->create_sub_node("sub_ns");
|
||||
}
|
||||
|
||||
rclcpp::Node::SharedPtr node_;
|
||||
rclcpp::Node::SharedPtr subnode_;
|
||||
};
|
||||
|
||||
/*
|
||||
Testing subscription construction and destruction for subnodes.
|
||||
*/
|
||||
TEST_F(TestSubscriptionSub, construction_and_destruction) {
|
||||
auto callback = [](test_msgs::msg::Empty::ConstSharedPtr msg) {
|
||||
(void)msg;
|
||||
};
|
||||
{
|
||||
auto sub = subnode_->create_subscription<test_msgs::msg::Empty>("topic", 1, callback);
|
||||
EXPECT_STREQ(sub->get_topic_name(), "/ns/sub_ns/topic");
|
||||
}
|
||||
|
||||
{
|
||||
auto sub = subnode_->create_subscription<test_msgs::msg::Empty>("/topic", 1, callback);
|
||||
EXPECT_STREQ(sub->get_topic_name(), "/topic");
|
||||
}
|
||||
|
||||
{
|
||||
auto sub = subnode_->create_subscription<test_msgs::msg::Empty>("~/topic", 1, callback);
|
||||
std::string expected_topic_name =
|
||||
std::string(node_->get_namespace()) + "/" + node_->get_name() + "/topic";
|
||||
EXPECT_STREQ(sub->get_topic_name(), expected_topic_name.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto sub = node_->create_subscription<test_msgs::msg::Empty>("invalid_topic?", 1, callback);
|
||||
}, rclcpp::exceptions::InvalidTopicNameError);
|
||||
}
|
||||
}
|
||||
|
||||
struct TestParameters final
|
||||
{
|
||||
TestParameters(rclcpp::QoS qos, std::string description)
|
||||
: qos(qos), description(description) {}
|
||||
rclcpp::QoS qos;
|
||||
std::string description;
|
||||
};
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, const TestParameters & params)
|
||||
{
|
||||
out << params.description;
|
||||
return out;
|
||||
}
|
||||
|
||||
class TestSubscriptionInvalidIntraprocessQos
|
||||
: public TestSubscription,
|
||||
public ::testing::WithParamInterface<TestParameters>
|
||||
{};
|
||||
|
||||
static std::vector<TestParameters> invalid_qos_profiles()
|
||||
{
|
||||
std::vector<TestParameters> parameters;
|
||||
|
||||
parameters.reserve(3);
|
||||
parameters.push_back(
|
||||
TestParameters(
|
||||
rclcpp::QoS(rclcpp::KeepLast(10)).transient_local(),
|
||||
"transient_local_qos"));
|
||||
parameters.push_back(
|
||||
TestParameters(
|
||||
rclcpp::QoS(rclcpp::KeepAll()),
|
||||
"keep_all_qos"));
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
TestSubscriptionThrows, TestSubscriptionInvalidIntraprocessQos,
|
||||
::testing::ValuesIn(invalid_qos_profiles()),
|
||||
::testing::PrintToStringParamName());
|
||||
|
||||
/*
|
||||
Testing subscription with intraprocess enabled and invalid QoS
|
||||
*/
|
||||
TEST_P(TestSubscriptionInvalidIntraprocessQos, test_subscription_throws) {
|
||||
initialize(rclcpp::NodeOptions().use_intra_process_comms(true));
|
||||
rclcpp::QoS qos = GetParam().qos;
|
||||
{
|
||||
auto callback = std::bind(
|
||||
&TestSubscriptionInvalidIntraprocessQos::on_message,
|
||||
this,
|
||||
std::placeholders::_1);
|
||||
|
||||
ASSERT_THROW(
|
||||
{auto subscription = node_->create_subscription<test_msgs::msg::Empty>(
|
||||
"topic",
|
||||
qos,
|
||||
callback);},
|
||||
std::invalid_argument);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Testing subscription with invalid use_intra_process_comm
|
||||
*/
|
||||
TEST_P(TestSubscriptionInvalidIntraprocessQos, test_subscription_throws_intraprocess) {
|
||||
rclcpp::SubscriptionOptionsWithAllocator<std::allocator<void>> options;
|
||||
options.use_intra_process_comm = static_cast<rclcpp::IntraProcessSetting>(5);
|
||||
|
||||
initialize();
|
||||
rclcpp::QoS qos = GetParam().qos;
|
||||
auto callback = std::bind(
|
||||
&TestSubscriptionInvalidIntraprocessQos::on_message,
|
||||
this,
|
||||
std::placeholders::_1);
|
||||
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
{auto subscription = node_->create_subscription<test_msgs::msg::Empty>(
|
||||
"topic",
|
||||
qos,
|
||||
callback,
|
||||
options);},
|
||||
std::runtime_error("Unrecognized IntraProcessSetting value"));
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ TEST_F(TestTimeSource, clock) {
|
||||
|
||||
trigger_clock_changes(node, ros_clock, false);
|
||||
|
||||
// Even now that we've recieved a message, ROS time should still not be active since the
|
||||
// Even now that we've received a message, ROS time should still not be active since the
|
||||
// parameter has not been explicitly set.
|
||||
EXPECT_FALSE(ros_clock->ros_time_is_active());
|
||||
|
||||
|
||||
@@ -73,6 +73,20 @@ protected:
|
||||
EXPECT_FALSE(timer->is_steady());
|
||||
break;
|
||||
}
|
||||
timer_without_autostart = test_node->create_wall_timer(
|
||||
100ms,
|
||||
[this]() -> void
|
||||
{
|
||||
this->has_timer_run.store(true);
|
||||
|
||||
if (this->cancel_timer.load()) {
|
||||
this->timer->cancel();
|
||||
}
|
||||
// prevent any tests running timer from blocking
|
||||
this->executor->cancel();
|
||||
}, nullptr, false);
|
||||
EXPECT_TRUE(timer_without_autostart->is_steady());
|
||||
|
||||
executor->add_node(test_node);
|
||||
// don't start spinning, let the test dictate when
|
||||
}
|
||||
@@ -93,6 +107,7 @@ protected:
|
||||
std::atomic<bool> cancel_timer;
|
||||
rclcpp::Node::SharedPtr test_node;
|
||||
std::shared_ptr<rclcpp::TimerBase> timer;
|
||||
std::shared_ptr<rclcpp::TimerBase> timer_without_autostart;
|
||||
std::shared_ptr<rclcpp::executors::SingleThreadedExecutor> executor;
|
||||
};
|
||||
|
||||
@@ -334,3 +349,18 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
return std::string("unknown");
|
||||
}
|
||||
);
|
||||
|
||||
/// Simple test of a timer without autostart
|
||||
TEST_P(TestTimer, test_timer_without_autostart)
|
||||
{
|
||||
EXPECT_TRUE(timer_without_autostart->is_canceled());
|
||||
EXPECT_EQ(
|
||||
timer_without_autostart->time_until_trigger().count(),
|
||||
std::chrono::nanoseconds::max().count());
|
||||
// Reset to change start timer
|
||||
timer_without_autostart->reset();
|
||||
EXPECT_LE(
|
||||
timer_without_autostart->time_until_trigger().count(),
|
||||
std::chrono::nanoseconds::max().count());
|
||||
EXPECT_FALSE(timer_without_autostart->is_canceled());
|
||||
}
|
||||
|
||||
@@ -3,6 +3,15 @@ Changelog for package rclcpp_action
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
22.1.0 (2023-08-21)
|
||||
-------------------
|
||||
|
||||
22.0.0 (2023-07-11)
|
||||
-------------------
|
||||
|
||||
21.3.0 (2023-06-12)
|
||||
-------------------
|
||||
|
||||
21.2.0 (2023-06-07)
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="2">
|
||||
<name>rclcpp_action</name>
|
||||
<version>21.2.0</version>
|
||||
<version>22.1.0</version>
|
||||
<description>Adds action APIs for C++.</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -2,6 +2,15 @@
|
||||
Changelog for package rclcpp_components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
22.1.0 (2023-08-21)
|
||||
-------------------
|
||||
|
||||
22.0.0 (2023-07-11)
|
||||
-------------------
|
||||
|
||||
21.3.0 (2023-06-12)
|
||||
-------------------
|
||||
|
||||
21.2.0 (2023-06-07)
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="2">
|
||||
<name>rclcpp_components</name>
|
||||
<version>21.2.0</version>
|
||||
<version>22.1.0</version>
|
||||
<description>Package containing tools for dynamically loadable components</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -3,6 +3,21 @@ Changelog for package rclcpp_lifecycle
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
22.1.0 (2023-08-21)
|
||||
-------------------
|
||||
* Stop using constref signature of benchmark DoNotOptimize. (`#2238 <https://github.com/ros2/rclcpp/issues/2238>`_)
|
||||
* Contributors: Chris Lalancette
|
||||
|
||||
22.0.0 (2023-07-11)
|
||||
-------------------
|
||||
* Implement get_node_type_descriptions_interface for lifecyclenode and add smoke test for it (`#2237 <https://github.com/ros2/rclcpp/issues/2237>`_)
|
||||
* Switch lifecycle to use the RCLCPP macros. (`#2233 <https://github.com/ros2/rclcpp/issues/2233>`_)
|
||||
* Add new node interface TypeDescriptionsInterface to provide GetTypeDescription service (`#2224 <https://github.com/ros2/rclcpp/issues/2224>`_)
|
||||
* Contributors: Chris Lalancette, Emerson Knapp
|
||||
|
||||
21.3.0 (2023-06-12)
|
||||
-------------------
|
||||
|
||||
21.2.0 (2023-06-07)
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
#include "rclcpp/node_interfaces/node_time_source_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_type_descriptions_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_waitables_interface.hpp"
|
||||
#include "rclcpp/parameter.hpp"
|
||||
#include "rclcpp/publisher.hpp"
|
||||
@@ -823,6 +824,14 @@ public:
|
||||
rclcpp::node_interfaces::NodeTimeSourceInterface::SharedPtr
|
||||
get_node_time_source_interface();
|
||||
|
||||
/// Return the Node's internal NodeTypeDescriptionsInterface implementation.
|
||||
/**
|
||||
* \sa rclcpp::Node::get_node_type_descriptions_interface
|
||||
*/
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr
|
||||
get_node_type_descriptions_interface();
|
||||
|
||||
/// Return the Node's internal NodeWaitablesInterface implementation.
|
||||
/**
|
||||
* \sa rclcpp::Node::get_node_waitables_interface
|
||||
@@ -1085,6 +1094,7 @@ private:
|
||||
rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock_;
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters_;
|
||||
rclcpp::node_interfaces::NodeTimeSourceInterface::SharedPtr node_time_source_;
|
||||
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr node_type_descriptions_;
|
||||
rclcpp::node_interfaces::NodeWaitablesInterface::SharedPtr node_waitables_;
|
||||
|
||||
const rclcpp::NodeOptions node_options_;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="2">
|
||||
<name>rclcpp_lifecycle</name>
|
||||
<version>21.2.0</version>
|
||||
<version>22.1.0</version>
|
||||
<description>Package containing a prototype for lifecycle implementation</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "rclcpp/node_interfaces/node_time_source.hpp"
|
||||
#include "rclcpp/node_interfaces/node_timers.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics.hpp"
|
||||
#include "rclcpp/node_interfaces/node_type_descriptions.hpp"
|
||||
#include "rclcpp/node_interfaces/node_waitables.hpp"
|
||||
#include "rclcpp/parameter_service.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
@@ -113,9 +114,15 @@ LifecycleNode::LifecycleNode(
|
||||
options.clock_qos(),
|
||||
options.use_clock_thread()
|
||||
)),
|
||||
node_type_descriptions_(new rclcpp::node_interfaces::NodeTypeDescriptions(
|
||||
node_base_,
|
||||
node_logging_,
|
||||
node_parameters_,
|
||||
node_services_
|
||||
)),
|
||||
node_waitables_(new rclcpp::node_interfaces::NodeWaitables(node_base_.get())),
|
||||
node_options_(options),
|
||||
impl_(new LifecycleNodeInterfaceImpl(node_base_, node_services_))
|
||||
impl_(new LifecycleNodeInterfaceImpl(node_base_, node_services_, node_logging_))
|
||||
{
|
||||
impl_->init(enable_communication_interface);
|
||||
|
||||
@@ -468,6 +475,12 @@ LifecycleNode::get_node_topics_interface()
|
||||
return node_topics_;
|
||||
}
|
||||
|
||||
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr
|
||||
LifecycleNode::get_node_type_descriptions_interface()
|
||||
{
|
||||
return node_type_descriptions_;
|
||||
}
|
||||
|
||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr
|
||||
LifecycleNode::get_node_services_interface()
|
||||
{
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "lifecycle_msgs/srv/get_available_transitions.hpp"
|
||||
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_logging_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_services_interface.hpp"
|
||||
|
||||
#include "rclcpp_lifecycle/node_interfaces/lifecycle_node_interface.hpp"
|
||||
@@ -50,9 +51,11 @@ namespace rclcpp_lifecycle
|
||||
|
||||
LifecycleNode::LifecycleNodeInterfaceImpl::LifecycleNodeInterfaceImpl(
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> node_base_interface,
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeServicesInterface> node_services_interface)
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeServicesInterface> node_services_interface,
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeLoggingInterface> node_logging_interface)
|
||||
: node_base_interface_(node_base_interface),
|
||||
node_services_interface_(node_services_interface)
|
||||
node_services_interface_(node_services_interface),
|
||||
node_logging_interface_(node_logging_interface)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -65,8 +68,8 @@ LifecycleNode::LifecycleNodeInterfaceImpl::~LifecycleNodeInterfaceImpl()
|
||||
ret = rcl_lifecycle_state_machine_fini(&state_machine_, node_handle);
|
||||
}
|
||||
if (ret != RCL_RET_OK) {
|
||||
RCUTILS_LOG_FATAL_NAMED(
|
||||
"rclcpp_lifecycle",
|
||||
RCLCPP_FATAL(
|
||||
node_logging_interface_->get_logger(),
|
||||
"failed to destroy rcl_state_machine");
|
||||
}
|
||||
}
|
||||
@@ -398,7 +401,8 @@ LifecycleNode::LifecycleNodeInterfaceImpl::change_state(
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(state_machine_mutex_);
|
||||
if (rcl_lifecycle_state_machine_is_initialized(&state_machine_) != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR(
|
||||
RCLCPP_ERROR(
|
||||
node_logging_interface_->get_logger(),
|
||||
"Unable to change state for state machine for %s: %s",
|
||||
node_base_interface_->get_name(), rcl_get_error_string().str);
|
||||
return RCL_RET_ERROR;
|
||||
@@ -411,7 +415,8 @@ LifecycleNode::LifecycleNodeInterfaceImpl::change_state(
|
||||
rcl_lifecycle_trigger_transition_by_id(
|
||||
&state_machine_, transition_id, publish_update) != RCL_RET_OK)
|
||||
{
|
||||
RCUTILS_LOG_ERROR(
|
||||
RCLCPP_ERROR(
|
||||
node_logging_interface_->get_logger(),
|
||||
"Unable to start transition %u from current state %s: %s",
|
||||
transition_id, state_machine_.current_state->label, rcl_get_error_string().str);
|
||||
rcutils_reset_error();
|
||||
@@ -443,7 +448,8 @@ LifecycleNode::LifecycleNodeInterfaceImpl::change_state(
|
||||
rcl_lifecycle_trigger_transition_by_label(
|
||||
&state_machine_, transition_label, publish_update) != RCL_RET_OK)
|
||||
{
|
||||
RCUTILS_LOG_ERROR(
|
||||
RCLCPP_ERROR(
|
||||
node_logging_interface_->get_logger(),
|
||||
"Failed to finish transition %u. Current state is now: %s (%s)",
|
||||
transition_id, state_machine_.current_state->label, rcl_get_error_string().str);
|
||||
rcutils_reset_error();
|
||||
@@ -458,7 +464,9 @@ LifecycleNode::LifecycleNodeInterfaceImpl::change_state(
|
||||
// error handling ?!
|
||||
// TODO(karsten1987): iterate over possible ret value
|
||||
if (cb_return_code == node_interfaces::LifecycleNodeInterface::CallbackReturn::ERROR) {
|
||||
RCUTILS_LOG_WARN("Error occurred while doing error handling.");
|
||||
RCLCPP_WARN(
|
||||
node_logging_interface_->get_logger(),
|
||||
"Error occurred while doing error handling.");
|
||||
|
||||
auto error_cb_code = execute_callback(current_state_id, initial_state);
|
||||
auto error_cb_label = get_label_for_return_code(error_cb_code);
|
||||
@@ -467,7 +475,9 @@ LifecycleNode::LifecycleNodeInterfaceImpl::change_state(
|
||||
rcl_lifecycle_trigger_transition_by_label(
|
||||
&state_machine_, error_cb_label, publish_update) != RCL_RET_OK)
|
||||
{
|
||||
RCUTILS_LOG_ERROR("Failed to call cleanup on error state: %s", rcl_get_error_string().str);
|
||||
RCLCPP_ERROR(
|
||||
node_logging_interface_->get_logger(),
|
||||
"Failed to call cleanup on error state: %s", rcl_get_error_string().str);
|
||||
rcutils_reset_error();
|
||||
return RCL_RET_ERROR;
|
||||
}
|
||||
@@ -495,8 +505,12 @@ LifecycleNode::LifecycleNodeInterfaceImpl::execute_callback(
|
||||
try {
|
||||
cb_success = callback(State(previous_state));
|
||||
} catch (const std::exception & e) {
|
||||
RCUTILS_LOG_ERROR("Caught exception in callback for transition %d", it->first);
|
||||
RCUTILS_LOG_ERROR("Original error: %s", e.what());
|
||||
RCLCPP_ERROR(
|
||||
node_logging_interface_->get_logger(),
|
||||
"Caught exception in callback for transition %d", it->first);
|
||||
RCLCPP_ERROR(
|
||||
node_logging_interface_->get_logger(),
|
||||
"Original error: %s", e.what());
|
||||
cb_success = node_interfaces::LifecycleNodeInterface::CallbackReturn::ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_logging_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_services_interface.hpp"
|
||||
|
||||
#include "rclcpp_lifecycle/node_interfaces/lifecycle_node_interface.hpp"
|
||||
@@ -52,7 +53,8 @@ class LifecycleNode::LifecycleNodeInterfaceImpl final
|
||||
public:
|
||||
LifecycleNodeInterfaceImpl(
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> node_base_interface,
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeServicesInterface> node_services_interface);
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeServicesInterface> node_services_interface,
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeLoggingInterface> node_logging_interface);
|
||||
|
||||
~LifecycleNodeInterfaceImpl();
|
||||
|
||||
@@ -152,6 +154,7 @@ private:
|
||||
|
||||
using NodeBasePtr = std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface>;
|
||||
using NodeServicesPtr = std::shared_ptr<rclcpp::node_interfaces::NodeServicesInterface>;
|
||||
using NodeLoggingPtr = std::shared_ptr<rclcpp::node_interfaces::NodeLoggingInterface>;
|
||||
using ChangeStateSrvPtr = std::shared_ptr<rclcpp::Service<ChangeStateSrv>>;
|
||||
using GetStateSrvPtr = std::shared_ptr<rclcpp::Service<GetStateSrv>>;
|
||||
using GetAvailableStatesSrvPtr =
|
||||
@@ -163,6 +166,7 @@ private:
|
||||
|
||||
NodeBasePtr node_base_interface_;
|
||||
NodeServicesPtr node_services_interface_;
|
||||
NodeLoggingPtr node_logging_interface_;
|
||||
ChangeStateSrvPtr srv_change_state_;
|
||||
GetStateSrvPtr srv_get_state_;
|
||||
GetAvailableStatesSrvPtr srv_get_available_states_;
|
||||
|
||||
@@ -228,7 +228,8 @@ protected:
|
||||
BENCHMARK_F(BenchmarkLifecycleClient, get_state)(benchmark::State & state) {
|
||||
for (auto _ : state) {
|
||||
(void)_;
|
||||
const auto lifecycle_state = lifecycle_client->get_state();
|
||||
|
||||
lifecycle_msgs::msg::State lifecycle_state = lifecycle_client->get_state();
|
||||
if (lifecycle_state.id != lifecycle_msgs::msg::State::PRIMARY_STATE_UNCONFIGURED) {
|
||||
const std::string msg =
|
||||
std::string("Expected state did not match actual: ") +
|
||||
@@ -268,7 +269,7 @@ BENCHMARK_F(BenchmarkLifecycleClient, get_available_states)(benchmark::State & s
|
||||
for (auto _ : state) {
|
||||
(void)_;
|
||||
constexpr size_t expected_states = 11u;
|
||||
const auto states = lifecycle_client->get_available_states();
|
||||
std::vector<lifecycle_msgs::msg::State> states = lifecycle_client->get_available_states();
|
||||
if (states.size() != expected_states) {
|
||||
const std::string msg =
|
||||
std::string("Expected number of states did not match actual: ") +
|
||||
@@ -284,7 +285,8 @@ BENCHMARK_F(BenchmarkLifecycleClient, get_available_transitions)(benchmark::Stat
|
||||
for (auto _ : state) {
|
||||
(void)_;
|
||||
constexpr size_t expected_transitions = 2u;
|
||||
const auto transitions = lifecycle_client->get_available_transitions();
|
||||
std::vector<lifecycle_msgs::msg::TransitionDescription> transitions =
|
||||
lifecycle_client->get_available_transitions();
|
||||
if (transitions.size() != expected_transitions) {
|
||||
const std::string msg =
|
||||
std::string("Expected number of transitions did not match actual: ") +
|
||||
@@ -300,7 +302,8 @@ BENCHMARK_F(BenchmarkLifecycleClient, get_transition_graph)(benchmark::State & s
|
||||
for (auto _ : state) {
|
||||
(void)_;
|
||||
constexpr size_t expected_transitions = 25u;
|
||||
const auto transitions = lifecycle_client->get_transition_graph();
|
||||
std::vector<lifecycle_msgs::msg::TransitionDescription> transitions =
|
||||
lifecycle_client->get_transition_graph();
|
||||
if (transitions.size() != expected_transitions) {
|
||||
const std::string msg =
|
||||
std::string("Expected number of transitions did not match actual: ") +
|
||||
|
||||
@@ -97,13 +97,15 @@ protected:
|
||||
BENCHMARK_F(BenchmarkLifecycleNode, get_current_state)(benchmark::State & state) {
|
||||
for (auto _ : state) {
|
||||
(void)_;
|
||||
const auto & lifecycle_state = node->get_current_state();
|
||||
const rclcpp_lifecycle::State & lifecycle_state = node->get_current_state();
|
||||
if (lifecycle_state.id() != lifecycle_msgs::msg::State::PRIMARY_STATE_UNCONFIGURED) {
|
||||
const std::string message =
|
||||
std::string("Node's current state is: ") + std::to_string(lifecycle_state.id());
|
||||
state.SkipWithError(message.c_str());
|
||||
}
|
||||
benchmark::DoNotOptimize(lifecycle_state);
|
||||
// Google benchmark 1.8.2 warns that the constref DoNotOptimize signature may be optimized away
|
||||
// by the compiler. Cast const away to ensure we don't get that problem (and warning).
|
||||
benchmark::DoNotOptimize(const_cast<rclcpp_lifecycle::State &>(lifecycle_state));
|
||||
benchmark::ClobberMemory();
|
||||
}
|
||||
}
|
||||
@@ -112,7 +114,7 @@ BENCHMARK_F(BenchmarkLifecycleNode, get_available_states)(benchmark::State & sta
|
||||
for (auto _ : state) {
|
||||
(void)_;
|
||||
constexpr size_t expected_states = 11u;
|
||||
const auto lifecycle_states = node->get_available_states();
|
||||
std::vector<rclcpp_lifecycle::State> lifecycle_states = node->get_available_states();
|
||||
if (lifecycle_states.size() != expected_states) {
|
||||
const std::string msg = std::to_string(lifecycle_states.size());
|
||||
state.SkipWithError(msg.c_str());
|
||||
@@ -126,7 +128,7 @@ BENCHMARK_F(BenchmarkLifecycleNode, get_available_transitions)(benchmark::State
|
||||
for (auto _ : state) {
|
||||
(void)_;
|
||||
constexpr size_t expected_transitions = 2u;
|
||||
const auto & transitions = node->get_available_transitions();
|
||||
std::vector<rclcpp_lifecycle::Transition> transitions = node->get_available_transitions();
|
||||
if (transitions.size() != expected_transitions) {
|
||||
const std::string msg = std::to_string(transitions.size());
|
||||
state.SkipWithError(msg.c_str());
|
||||
@@ -140,7 +142,7 @@ BENCHMARK_F(BenchmarkLifecycleNode, get_transition_graph)(benchmark::State & sta
|
||||
for (auto _ : state) {
|
||||
(void)_;
|
||||
constexpr size_t expected_transitions = 25u;
|
||||
const auto & transitions = node->get_transition_graph();
|
||||
std::vector<rclcpp_lifecycle::Transition> transitions = node->get_transition_graph();
|
||||
if (transitions.size() != expected_transitions) {
|
||||
const std::string msg =
|
||||
std::string("Expected number of transitions did not match actual: ") +
|
||||
@@ -162,18 +164,20 @@ BENCHMARK_F(BenchmarkLifecycleNode, transition_valid_state)(benchmark::State & s
|
||||
reset_heap_counters();
|
||||
for (auto _ : state) {
|
||||
(void)_;
|
||||
const auto & active =
|
||||
const rclcpp_lifecycle::State & active =
|
||||
node->trigger_transition(lifecycle_msgs::msg::Transition::TRANSITION_ACTIVATE);
|
||||
if (active.id() != lifecycle_msgs::msg::State::PRIMARY_STATE_ACTIVE) {
|
||||
state.SkipWithError("Transition to active state failed");
|
||||
}
|
||||
const auto & inactive =
|
||||
const rclcpp_lifecycle::State & inactive =
|
||||
node->trigger_transition(lifecycle_msgs::msg::Transition::TRANSITION_DEACTIVATE);
|
||||
if (inactive.id() != lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE) {
|
||||
state.SkipWithError("Transition to inactive state failed");
|
||||
}
|
||||
benchmark::DoNotOptimize(active);
|
||||
benchmark::DoNotOptimize(inactive);
|
||||
// Google benchmark 1.8.2 warns that the constref DoNotOptimize signature may be optimized away
|
||||
// by the compiler. Cast const away to ensure we don't get that problem (and warning).
|
||||
benchmark::DoNotOptimize(const_cast<rclcpp_lifecycle::State &>(active));
|
||||
benchmark::DoNotOptimize(const_cast<rclcpp_lifecycle::State &>(inactive));
|
||||
benchmark::ClobberMemory();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,11 +427,15 @@ TEST_F(TestDefaultStateMachine, lifecycle_subscriber) {
|
||||
// Parameters are tested more thoroughly in rclcpp's test_node.cpp
|
||||
// These are provided for coverage of lifecycle node's API
|
||||
TEST_F(TestDefaultStateMachine, declare_parameters) {
|
||||
// "start_type_description_service" and "use_sim_time"
|
||||
const uint64_t builtin_param_count = 2;
|
||||
const uint64_t expected_param_count = 6 + builtin_param_count;
|
||||
auto test_node = std::make_shared<EmptyLifecycleNode>("testnode");
|
||||
|
||||
auto list_result = test_node->list_parameters({}, 0u);
|
||||
EXPECT_EQ(list_result.names.size(), 1u);
|
||||
EXPECT_STREQ(list_result.names[0].c_str(), "use_sim_time");
|
||||
EXPECT_EQ(list_result.names.size(), builtin_param_count);
|
||||
EXPECT_STREQ(list_result.names[0].c_str(), "start_type_description_service");
|
||||
EXPECT_STREQ(list_result.names[1].c_str(), "use_sim_time");
|
||||
|
||||
const std::string bool_name = "test_boolean";
|
||||
const std::string int_name = "test_int";
|
||||
@@ -469,10 +473,11 @@ TEST_F(TestDefaultStateMachine, declare_parameters) {
|
||||
test_node->declare_parameters("test_double", double_parameters);
|
||||
|
||||
list_result = test_node->list_parameters({}, 0u);
|
||||
EXPECT_EQ(list_result.names.size(), 7u);
|
||||
EXPECT_EQ(list_result.names.size(), expected_param_count);
|
||||
|
||||
// The order of these names is not controlled by lifecycle_node, doing set equality
|
||||
std::set<std::string> expected_names = {
|
||||
"start_type_description_service",
|
||||
"test_boolean",
|
||||
"test_double.double_one",
|
||||
"test_double.double_two",
|
||||
@@ -487,11 +492,13 @@ TEST_F(TestDefaultStateMachine, declare_parameters) {
|
||||
}
|
||||
|
||||
TEST_F(TestDefaultStateMachine, check_parameters) {
|
||||
const uint64_t builtin_param_count = 2;
|
||||
auto test_node = std::make_shared<EmptyLifecycleNode>("testnode");
|
||||
|
||||
auto list_result = test_node->list_parameters({}, 0u);
|
||||
EXPECT_EQ(list_result.names.size(), 1u);
|
||||
EXPECT_STREQ(list_result.names[0].c_str(), "use_sim_time");
|
||||
EXPECT_EQ(list_result.names.size(), builtin_param_count);
|
||||
EXPECT_STREQ(list_result.names[0].c_str(), "start_type_description_service");
|
||||
EXPECT_STREQ(list_result.names[1].c_str(), "use_sim_time");
|
||||
|
||||
const std::string bool_name = "test_boolean";
|
||||
const std::string int_name = "test_int";
|
||||
@@ -549,8 +556,7 @@ TEST_F(TestDefaultStateMachine, check_parameters) {
|
||||
std::map<std::string, rclcpp::ParameterValue> parameter_map;
|
||||
EXPECT_TRUE(test_node->get_parameters({}, parameter_map));
|
||||
|
||||
// int param, bool param, and use_sim_time
|
||||
EXPECT_EQ(parameter_map.size(), 3u);
|
||||
EXPECT_EQ(parameter_map.size(), parameter_names.size() + builtin_param_count);
|
||||
|
||||
// Check parameter types
|
||||
auto parameter_types = test_node->get_parameter_types(parameter_names);
|
||||
@@ -585,10 +591,12 @@ TEST_F(TestDefaultStateMachine, check_parameters) {
|
||||
|
||||
// List parameters
|
||||
list_result = test_node->list_parameters({}, 0u);
|
||||
EXPECT_EQ(list_result.names.size(), 3u);
|
||||
EXPECT_STREQ(list_result.names[0].c_str(), parameter_names[0].c_str());
|
||||
EXPECT_STREQ(list_result.names[1].c_str(), parameter_names[1].c_str());
|
||||
EXPECT_STREQ(list_result.names[2].c_str(), "use_sim_time");
|
||||
EXPECT_EQ(list_result.names.size(), parameter_names.size() + builtin_param_count);
|
||||
size_t index = 0;
|
||||
EXPECT_STREQ(list_result.names[index++].c_str(), "start_type_description_service");
|
||||
EXPECT_STREQ(list_result.names[index++].c_str(), parameter_names[0].c_str());
|
||||
EXPECT_STREQ(list_result.names[index++].c_str(), parameter_names[1].c_str());
|
||||
EXPECT_STREQ(list_result.names[index++].c_str(), "use_sim_time");
|
||||
|
||||
// Undeclare parameter
|
||||
test_node->undeclare_parameter(bool_name);
|
||||
@@ -633,6 +641,7 @@ TEST_F(TestDefaultStateMachine, test_getters) {
|
||||
EXPECT_LT(0u, test_node->now().nanoseconds());
|
||||
EXPECT_STREQ("testnode", test_node->get_logger().get_name());
|
||||
EXPECT_NE(nullptr, const_cast<const EmptyLifecycleNode *>(test_node.get())->get_clock());
|
||||
EXPECT_NE(nullptr, test_node->get_node_type_descriptions_interface());
|
||||
}
|
||||
|
||||
TEST_F(TestDefaultStateMachine, test_graph_topics) {
|
||||
|
||||
Reference in New Issue
Block a user