Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c21065e979 | ||
|
|
c4ee11a5c7 | ||
|
|
14ecbc3f0b | ||
|
|
8a4cb48b2c | ||
|
|
aa634b28df | ||
|
|
8ec31edd4a | ||
|
|
a709d81a93 | ||
|
|
a35793ad28 | ||
|
|
7cba3c4882 | ||
|
|
27e800b910 | ||
|
|
e6f6b2a7ad | ||
|
|
6c95d10cca | ||
|
|
a5a7febb60 | ||
|
|
7373669455 | ||
|
|
ae930aa2e5 | ||
|
|
24846c3109 | ||
|
|
160da7b432 | ||
|
|
22939ddf9b | ||
|
|
ea1d764f42 | ||
|
|
82666affcd | ||
|
|
0be3acf32f | ||
|
|
34005e903f | ||
|
|
288be9c981 | ||
|
|
93028ff38d | ||
|
|
8b9691f42d | ||
|
|
40e3fb78db | ||
|
|
11afffad50 | ||
|
|
8e49befce9 | ||
|
|
f78ed952b2 | ||
|
|
2420c48514 | ||
|
|
c01602f7a6 | ||
|
|
6ad551a5cc | ||
|
|
0162861fa1 | ||
|
|
6040228d13 |
@@ -2,6 +2,46 @@
|
||||
Changelog for package rclcpp
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
29.5.3 (2025-09-11)
|
||||
-------------------
|
||||
* Fix: improve exception context for parameter_value_from (`#2917 <https://github.com/ros2/rclcpp/issues/2917>`_) (`#2919 <https://github.com/ros2/rclcpp/issues/2919>`_)
|
||||
* Allow for implicitly convertable loggers as well (`#2922 <https://github.com/ros2/rclcpp/issues/2922>`_) (`#2936 <https://github.com/ros2/rclcpp/issues/2936>`_)
|
||||
* Fix `start_type_description_service` param handling (`#2897 <https://github.com/ros2/rclcpp/issues/2897>`_) (`#2908 <https://github.com/ros2/rclcpp/issues/2908>`_)
|
||||
* Add qos parameter for wait_for_message function (`#2903 <https://github.com/ros2/rclcpp/issues/2903>`_) (`#2905 <https://github.com/ros2/rclcpp/issues/2905>`_)
|
||||
* Expose `typesupport_helpers` API needed for the Rosbag2 (`#2858 <https://github.com/ros2/rclcpp/issues/2858>`_) (`#2901 <https://github.com/ros2/rclcpp/issues/2901>`_)
|
||||
* Fujitatomoya/test append parameter override (`#2896 <https://github.com/ros2/rclcpp/issues/2896>`_) (`#2899 <https://github.com/ros2/rclcpp/issues/2899>`_)
|
||||
* Add overload of `append_parameter_override` (`#2891 <https://github.com/ros2/rclcpp/issues/2891>`_) (`#2894 <https://github.com/ros2/rclcpp/issues/2894>`_)
|
||||
* Contributors: Tim Clephas, mergify[bot]
|
||||
|
||||
29.5.2 (2025-07-07)
|
||||
-------------------
|
||||
* Shutdown deadlock fix jazzy (`#2887 <https://github.com/ros2/rclcpp/issues/2887>`_) (`#2888 <https://github.com/ros2/rclcpp/issues/2888>`_)
|
||||
* Fix test_publisher_with_system_default_qos (`#2881 <https://github.com/ros2/rclcpp/issues/2881>`_) (`#2884 <https://github.com/ros2/rclcpp/issues/2884>`_)
|
||||
* Contributors: Tomoya Fujita, Janosch Machowinski
|
||||
|
||||
29.5.1 (2025-06-23)
|
||||
-------------------
|
||||
* Removed warning test_qos (`#2859 <https://github.com/ros2/rclcpp/issues/2859>`_) (`#2873 <https://github.com/ros2/rclcpp/issues/2873>`_)
|
||||
* Fix for memory leaks in rclcpp::SerializedMessage (`#2861 <https://github.com/ros2/rclcpp/issues/2861>`_) (`#2863 <https://github.com/ros2/rclcpp/issues/2863>`_)
|
||||
* get_all_data_impl() does not handle null pointers properly, causing segmentation fault (backport `#2840 <https://github.com/ros2/rclcpp/issues/2840>`_) (`#2850 <https://github.com/ros2/rclcpp/issues/2850>`_)
|
||||
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_) (`#2855 <https://github.com/ros2/rclcpp/issues/2855>`_)
|
||||
* QoSInitialization::from_rmw does not validate invalid history policy values, leading to silent failures (`#2841 <https://github.com/ros2/rclcpp/issues/2841>`_) (`#2846 <https://github.com/ros2/rclcpp/issues/2846>`_)
|
||||
* Add missing 's' to 'NodeParametersInterface' in doc/comment (`#2831 <https://github.com/ros2/rclcpp/issues/2831>`_) (`#2833 <https://github.com/ros2/rclcpp/issues/2833>`_)
|
||||
* subordinate node consistent behavior and update docstring. (`#2822 <https://github.com/ros2/rclcpp/issues/2822>`_) (`#2830 <https://github.com/ros2/rclcpp/issues/2830>`_)
|
||||
* throws std::invalid_argument if ParameterEvent is NULL. (`#2814 <https://github.com/ros2/rclcpp/issues/2814>`_)
|
||||
* Removed clang warnings (`#2823 <https://github.com/ros2/rclcpp/issues/2823>`_)
|
||||
* Contributors: Alejandro Hernández Cordero, Tomoya Fujita, mergify[bot]
|
||||
|
||||
29.5.0 (2025-04-18)
|
||||
-------------------
|
||||
* Fix a race condition (`#2819 <https://github.com/ros2/rclcpp/issues/2819>`_)
|
||||
* Remove redundant typesupport check in serialization module (`#2808 <https://github.com/ros2/rclcpp/issues/2808>`_)
|
||||
* Remove get_typesupport_handle implementation. (`#2806 <https://github.com/ros2/rclcpp/issues/2806>`_)
|
||||
* Use NodeParameterInterface instead of /parameter_event to update "use_sim_time" (`#2378 <https://github.com/ros2/rclcpp/issues/2378>`_)
|
||||
* Remove cancel_clock_executor_promise\_. (`#2797 <https://github.com/ros2/rclcpp/issues/2797>`_)
|
||||
* Enable parameter update recursively only when QoS override parameters. (`#2742 <https://github.com/ros2/rclcpp/issues/2742>`_)
|
||||
* Contributors: Pedro de Azeredo, Tanishq Chaudhary, Tomoya Fujita
|
||||
|
||||
29.4.0 (2025-04-04)
|
||||
-------------------
|
||||
* Removed trailing whitespace from the codebase. (`#2791 <https://github.com/ros2/rclcpp/issues/2791>`_)
|
||||
|
||||
@@ -97,6 +97,9 @@ declare_parameter_or_get(
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor)
|
||||
{
|
||||
try {
|
||||
// enable parameter modification to make it possible
|
||||
// to declare QoS override parameters during parameter callbacks.
|
||||
parameters_interface.enable_parameter_modification();
|
||||
return parameters_interface.declare_parameter(
|
||||
param_name, param_value, descriptor);
|
||||
} catch (const rclcpp::exceptions::ParameterAlreadyDeclaredException &) {
|
||||
|
||||
@@ -255,9 +255,13 @@ private:
|
||||
std::vector<BufferT> result_vtr;
|
||||
result_vtr.reserve(size_);
|
||||
for (size_t id = 0; id < size_; ++id) {
|
||||
result_vtr.emplace_back(
|
||||
new typename is_std_unique_ptr<T>::Ptr_type(
|
||||
*(ring_buffer_[(read_index_ + id) % capacity_])));
|
||||
const auto & elem(ring_buffer_[(read_index_ + id) % capacity_]);
|
||||
if (elem != nullptr) {
|
||||
result_vtr.emplace_back(new typename is_std_unique_ptr<T>::Ptr_type(
|
||||
*elem));
|
||||
} else {
|
||||
result_vtr.emplace_back(nullptr);
|
||||
}
|
||||
}
|
||||
return result_vtr;
|
||||
}
|
||||
|
||||
@@ -1559,6 +1559,10 @@ public:
|
||||
* which has been created using an existing instance of this class, but which
|
||||
* has an additional sub-namespace (short for subordinate namespace)
|
||||
* associated with it.
|
||||
* A subordinate node and an instance of this class share all the node interfaces
|
||||
* such as `rclcpp::node_interfaces::NodeParametersInterface`.
|
||||
* Subordinate nodes are primarily used to organize namespaces and provide a
|
||||
* hierarchical structure, but they are not meant to be completely independent nodes.
|
||||
* The sub-namespace will extend the node's namespace for the purpose of
|
||||
* creating additional entities, such as Publishers, Subscriptions, Service
|
||||
* Clients and Servers, and so on.
|
||||
|
||||
@@ -323,11 +323,9 @@ template<typename ParameterT>
|
||||
bool
|
||||
Node::get_parameter(const std::string & name, ParameterT & parameter) const
|
||||
{
|
||||
std::string sub_name = extend_name_with_sub_namespace(name, this->get_sub_namespace());
|
||||
|
||||
rclcpp::Parameter parameter_variant;
|
||||
|
||||
bool result = get_parameter(sub_name, parameter_variant);
|
||||
bool result = get_parameter(name, parameter_variant);
|
||||
if (result) {
|
||||
parameter = static_cast<ParameterT>(parameter_variant.get_value<ParameterT>());
|
||||
}
|
||||
@@ -342,9 +340,7 @@ Node::get_parameter_or(
|
||||
ParameterT & parameter,
|
||||
const ParameterT & alternative_value) const
|
||||
{
|
||||
std::string sub_name = extend_name_with_sub_namespace(name, this->get_sub_namespace());
|
||||
|
||||
bool got_parameter = get_parameter(sub_name, parameter);
|
||||
bool got_parameter = get_parameter(name, parameter);
|
||||
if (!got_parameter) {
|
||||
parameter = alternative_value;
|
||||
}
|
||||
|
||||
@@ -214,6 +214,10 @@ public:
|
||||
const std::map<std::string, rclcpp::ParameterValue> &
|
||||
get_parameter_overrides() const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
enable_parameter_modification() override;
|
||||
|
||||
using PreSetCallbacksHandleContainer = std::list<PreSetParametersCallbackHandle::WeakPtr>;
|
||||
using OnSetCallbacksHandleContainer = std::list<OnSetParametersCallbackHandle::WeakPtr>;
|
||||
using PostSetCallbacksHandleContainer = std::list<PostSetParametersCallbackHandle::WeakPtr>;
|
||||
|
||||
@@ -270,6 +270,26 @@ public:
|
||||
virtual
|
||||
const std::map<std::string, rclcpp::ParameterValue> &
|
||||
get_parameter_overrides() const = 0;
|
||||
|
||||
/// Enable parameter modification recursively during parameter callbacks.
|
||||
/**
|
||||
* This function is used to enable parameter modification during parameter callbacks.
|
||||
*
|
||||
* There are times when it does not allow parameter modification, such as when the parameter
|
||||
* callbacks are being called and tries to modify the parameters with set_parameter and
|
||||
* declare_parameter to avoid recursive parameter modification.
|
||||
* This is protected by rclcpp::node_interfaces::ParameterMutationRecursionGuard.
|
||||
*
|
||||
* This function is explicitly called to allow the recursive parameter operation during
|
||||
* parameter callbacks by the application.
|
||||
* Once it is enabled, the next parameter operation set/declare/undeclare_parameter are
|
||||
* allowed to execute in the parameter callback. But, no more further recursive operation
|
||||
* is allowed, unless user application calls this API again.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
enable_parameter_modification() = 0;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
|
||||
@@ -146,6 +146,14 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Append a single parameter override, parameter idiom style.
|
||||
NodeOptions &
|
||||
append_parameter_override(const rclcpp::Parameter & param)
|
||||
{
|
||||
this->parameter_overrides().push_back(param);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Return the use_global_arguments flag.
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
|
||||
@@ -45,6 +45,7 @@ public:
|
||||
* \param[in] names A list of parameter names of interest.
|
||||
* \param[in] types A list of the types of parameter events of iterest.
|
||||
* EventType NEW, DELETED, or CHANGED
|
||||
* \throws std::invalid_argument if event is NULL.
|
||||
*
|
||||
* Example Usage:
|
||||
*
|
||||
|
||||
@@ -29,26 +29,48 @@
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
/// Load the type support library for the given type.
|
||||
/**
|
||||
* \param[in] type The topic type, e.g. "std_msgs/msg/String"
|
||||
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
|
||||
* \return A shared library
|
||||
*/
|
||||
|
||||
/// \brief Extract the package name, middle module, and type name from a full type string.
|
||||
/// \details This function takes a full type string (e.g., "std_msgs/msg/String") and extracts
|
||||
/// the package name, middle module (if any), and type name. The middle module is the part
|
||||
/// between the package name and the type name, which is typically used for message types.
|
||||
/// For example, for "std_msgs/msg/String", it returns ("std_msgs", "msg", "String").
|
||||
/// \param[in] full_type
|
||||
/// \throws std::runtime_error if the input full type string is malformed or does not follow the
|
||||
/// expected format.
|
||||
/// \return A tuple containing the package name, middle module (if any), and type name.
|
||||
RCLCPP_PUBLIC
|
||||
std::tuple<std::string, std::string, std::string>
|
||||
extract_type_identifier(const std::string & full_type);
|
||||
|
||||
/// \brief Look for the library in the ament prefix paths and return the path to the type support
|
||||
/// library.
|
||||
/// \param[in] package_name The name of the package containing the type support library,
|
||||
/// e.g. "std_msgs".
|
||||
/// \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
|
||||
/// \throws std::runtime_error if the library is not found.
|
||||
/// \return The path to the type support library.
|
||||
RCLCPP_PUBLIC
|
||||
std::string get_typesupport_library_path(
|
||||
const std::string & package_name, const std::string & typesupport_identifier);
|
||||
|
||||
/// \brief Load the type support library for the given type.
|
||||
/// \param[in] type The topic type, e.g. "std_msgs/msg/String"
|
||||
/// \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
|
||||
/// \throws std::runtime_error if the library is not found or cannot be loaded.
|
||||
/// \return A shared library
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_ptr<rcpputils::SharedLibrary>
|
||||
get_typesupport_library(const std::string & type, const std::string & typesupport_identifier);
|
||||
|
||||
/// Extract the message type support handle from the library.
|
||||
/**
|
||||
* The library needs to match the topic type. The shared library must stay loaded for the lifetime of the result.
|
||||
*
|
||||
* \param[in] type The topic type, e.g. "std_msgs/msg/String"
|
||||
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
|
||||
* \param[in] library The shared type support library
|
||||
* \throws std::runtime_error if the symbol of type not found in the library.
|
||||
* \return A message type support handle
|
||||
*/
|
||||
/// \brief Extracts the message type support handle from the library.
|
||||
/// \note The library needs to match the topic type. The shared library must stay loaded for the
|
||||
/// lifetime of the result.
|
||||
/// \param[in] type The topic type, e.g. "std_msgs/msg/String"
|
||||
/// \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
|
||||
/// \param[in] library The shared type support library
|
||||
/// \throws std::runtime_error if the symbol of type not found in the library.
|
||||
/// \return A message type support handle
|
||||
RCLCPP_PUBLIC
|
||||
const rosidl_message_type_support_t *
|
||||
get_message_typesupport_handle(
|
||||
@@ -56,16 +78,14 @@ get_message_typesupport_handle(
|
||||
const std::string & typesupport_identifier,
|
||||
rcpputils::SharedLibrary & library);
|
||||
|
||||
/// Extract the service type support handle from the library.
|
||||
/**
|
||||
* The library needs to match the service type. The shared library must stay loaded for the lifetime of the result.
|
||||
*
|
||||
* \param[in] type The service type, e.g. "std_srvs/srv/Empty"
|
||||
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
|
||||
* \param[in] library The shared type support library
|
||||
* \throws std::runtime_error if the symbol of type not found in the library.
|
||||
* \return A service type support handle
|
||||
*/
|
||||
/// \brief Extracts the service type support handle from the library.
|
||||
/// \note The library needs to match the service type. The shared library must stay loaded for the
|
||||
/// lifetime of the result.
|
||||
/// \param[in] type The service type, e.g. "std_srvs/srv/Empty"
|
||||
/// \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
|
||||
/// \param[in] library The shared type support library
|
||||
/// \throws std::runtime_error if the symbol of type not found in the library.
|
||||
/// \return A service type support handle
|
||||
RCLCPP_PUBLIC
|
||||
const rosidl_service_type_support_t *
|
||||
get_service_typesupport_handle(
|
||||
@@ -73,17 +93,14 @@ get_service_typesupport_handle(
|
||||
const std::string & typesupport_identifier,
|
||||
rcpputils::SharedLibrary & library);
|
||||
|
||||
/// Extract the action type support handle from the library.
|
||||
/**
|
||||
* The library needs to match the action type. The shared library must stay loaded for the lifetime
|
||||
* of the result.
|
||||
*
|
||||
* \param[in] type The action type, e.g. "example_interfaces/action/Fibonacci"
|
||||
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
|
||||
* \param[in] library The shared type support library
|
||||
* \throws std::runtime_error if the symbol of type not found in the library.
|
||||
* \return A action type support handle
|
||||
*/
|
||||
/// \brief Extracts the action type support handle from the library.
|
||||
/// \note The library needs to match the action type. The shared library must stay loaded for the
|
||||
/// lifetime of the result.
|
||||
/// \param[in] type The action type, e.g. "example_interfaces/action/Fibonacci"
|
||||
/// \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
|
||||
/// \param[in] library The shared type support library
|
||||
/// \throws std::runtime_error if the symbol of type not found in the library.
|
||||
/// \return A action type support handle
|
||||
RCLCPP_PUBLIC
|
||||
const rosidl_action_type_support_t *
|
||||
get_action_typesupport_handle(
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef RCLCPP__WAIT_FOR_MESSAGE_HPP_
|
||||
#define RCLCPP__WAIT_FOR_MESSAGE_HPP_
|
||||
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
@@ -23,6 +24,7 @@
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
#include "rclcpp/wait_set.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
@@ -79,10 +81,11 @@ bool wait_for_message(
|
||||
/**
|
||||
* Wait for the next incoming message to arrive on a specified topic before the specified timeout.
|
||||
*
|
||||
* \param[out] out is the message to be filled when a new message is arriving.
|
||||
* \param[out] out is the message to be filled when a new message is arriving
|
||||
* \param[in] node the node pointer to initialize the subscription on.
|
||||
* \param[in] topic the topic to wait for messages.
|
||||
* \param[in] time_to_wait parameter specifying the timeout before returning.
|
||||
* \param[in] qos parameter specifying QoS settings for the subscription.
|
||||
* \return true if a message was successfully received, false if message could not
|
||||
* be obtained or shutdown was triggered asynchronously on the context.
|
||||
*/
|
||||
@@ -91,9 +94,10 @@ bool wait_for_message(
|
||||
MsgT & out,
|
||||
rclcpp::Node::SharedPtr node,
|
||||
const std::string & topic,
|
||||
std::chrono::duration<Rep, Period> time_to_wait = std::chrono::duration<Rep, Period>(-1))
|
||||
std::chrono::duration<Rep, Period> time_to_wait = std::chrono::duration<Rep, Period>(-1),
|
||||
const rclcpp::QoS & qos = rclcpp::SystemDefaultsQoS())
|
||||
{
|
||||
auto sub = node->create_subscription<MsgT>(topic, 1, [](const std::shared_ptr<const MsgT>) {});
|
||||
auto sub = node->create_subscription<MsgT>(topic, qos, [](const std::shared_ptr<const MsgT>) {});
|
||||
return wait_for_message<MsgT, Rep, Period>(
|
||||
out, sub, node->get_node_options().context(), time_to_wait);
|
||||
}
|
||||
|
||||
@@ -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>29.4.0</version>
|
||||
<version>29.5.3</version>
|
||||
<description>The ROS client library in C++.</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -124,8 +124,7 @@ def get_rclcpp_suffix_from_features(features):
|
||||
) \
|
||||
do { \
|
||||
static_assert( \
|
||||
::std::is_same<typename std::remove_cv_t<typename std::remove_reference_t<decltype(logger)>>, \
|
||||
typename ::rclcpp::Logger>::value, \
|
||||
::std::is_convertible_v<decltype(logger), ::rclcpp::Logger>, \
|
||||
"First argument to logging macros must be an rclcpp::Logger"); \
|
||||
@[ if 'throttle' in feature_combination]@ \
|
||||
auto get_time_point = [&c=clock](rcutils_time_point_value_t * time_point) -> rcutils_ret_t { \
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "rclcpp/context.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
@@ -142,11 +143,52 @@ rclcpp_logging_output_handler(
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
/**
|
||||
* Global storage for pre and post shutdown recursive mutexes.
|
||||
* Note, this is a ABI compatibility hack.
|
||||
*/
|
||||
class MutexLookup
|
||||
{
|
||||
std::mutex m;
|
||||
|
||||
struct MutexHolder
|
||||
{
|
||||
std::recursive_mutex on_shutdown_callbacks_mutex_;
|
||||
std::recursive_mutex pre_shutdown_callbacks_mutex_;
|
||||
};
|
||||
|
||||
std::map<const Context *, std::unique_ptr<MutexHolder>> mutexMap;
|
||||
|
||||
public:
|
||||
MutexHolder & getMutexes(const Context *forContext)
|
||||
{
|
||||
auto it = mutexMap.find(forContext);
|
||||
if(it == mutexMap.end()) {
|
||||
it = mutexMap.emplace(forContext, std::make_unique<MutexHolder>()).first;
|
||||
}
|
||||
|
||||
return *(it->second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only supposed to be called on deletion of context
|
||||
*/
|
||||
void removeMutexes(const Context *forContext)
|
||||
{
|
||||
mutexMap.erase(forContext);
|
||||
}
|
||||
};
|
||||
|
||||
MutexLookup mutexStorage;
|
||||
|
||||
Context::Context()
|
||||
: rcl_context_(nullptr),
|
||||
shutdown_reason_(""),
|
||||
logging_mutex_(nullptr)
|
||||
{}
|
||||
{
|
||||
// allocate mutexes
|
||||
mutexStorage.getMutexes(this);
|
||||
}
|
||||
|
||||
Context::~Context()
|
||||
{
|
||||
@@ -165,6 +207,9 @@ Context::~Context()
|
||||
} catch (...) {
|
||||
RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "unhandled exception in ~Context()");
|
||||
}
|
||||
|
||||
// delete mutexes
|
||||
mutexStorage.removeMutexes(this);
|
||||
}
|
||||
|
||||
RCLCPP_LOCAL
|
||||
@@ -310,9 +355,17 @@ Context::shutdown(const std::string & reason)
|
||||
|
||||
// call each pre-shutdown callback
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{pre_shutdown_callbacks_mutex_};
|
||||
for (const auto & callback : pre_shutdown_callbacks_) {
|
||||
(*callback)();
|
||||
std::lock_guard<std::recursive_mutex> lock{mutexStorage.getMutexes(
|
||||
this).pre_shutdown_callbacks_mutex_};
|
||||
// callbacks may delete other callbacks during the execution,
|
||||
// therefore we need to save a copy and check before execution
|
||||
// if the next callback is still present
|
||||
auto cpy = pre_shutdown_callbacks_;
|
||||
for (const auto & callback : cpy) {
|
||||
auto it = std::find(pre_shutdown_callbacks_.begin(), pre_shutdown_callbacks_.end(), callback);
|
||||
if(it != pre_shutdown_callbacks_.end()) {
|
||||
(*callback)();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,9 +378,17 @@ Context::shutdown(const std::string & reason)
|
||||
shutdown_reason_ = reason;
|
||||
// call each shutdown callback
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
|
||||
for (const auto & callback : on_shutdown_callbacks_) {
|
||||
(*callback)();
|
||||
std::lock_guard<std::recursive_mutex> lock(mutexStorage.getMutexes(
|
||||
this).on_shutdown_callbacks_mutex_);
|
||||
// callbacks may delete other callbacks during the execution,
|
||||
// therefore we need to save a copy and check before execution
|
||||
// if the next callback is still present
|
||||
auto cpy = on_shutdown_callbacks_;
|
||||
for (const auto & callback : cpy) {
|
||||
auto it = std::find(on_shutdown_callbacks_.begin(), on_shutdown_callbacks_.end(), callback);
|
||||
if(it != on_shutdown_callbacks_.end()) {
|
||||
(*callback)();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,10 +459,12 @@ Context::add_shutdown_callback(
|
||||
shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
|
||||
|
||||
if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
|
||||
std::lock_guard<std::mutex> lock(pre_shutdown_callbacks_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(mutexStorage.getMutexes(
|
||||
this).pre_shutdown_callbacks_mutex_);
|
||||
pre_shutdown_callbacks_.emplace_back(callback_shared_ptr);
|
||||
} else {
|
||||
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(mutexStorage.getMutexes(
|
||||
this).on_shutdown_callbacks_mutex_);
|
||||
on_shutdown_callbacks_.emplace_back(callback_shared_ptr);
|
||||
}
|
||||
|
||||
@@ -421,7 +484,7 @@ Context::remove_shutdown_callback(
|
||||
}
|
||||
|
||||
const auto remove_callback = [&callback_shared_ptr](auto & mutex, auto & callback_vector) {
|
||||
const std::lock_guard<std::mutex> lock(mutex);
|
||||
const std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||
auto iter = callback_vector.begin();
|
||||
for (; iter != callback_vector.end(); iter++) {
|
||||
if ((*iter).get() == callback_shared_ptr.get()) {
|
||||
@@ -432,6 +495,7 @@ Context::remove_shutdown_callback(
|
||||
return false;
|
||||
}
|
||||
callback_vector.erase(iter);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -439,9 +503,11 @@ Context::remove_shutdown_callback(
|
||||
shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
|
||||
|
||||
if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
|
||||
return remove_callback(pre_shutdown_callbacks_mutex_, pre_shutdown_callbacks_);
|
||||
return remove_callback(mutexStorage.getMutexes(this).pre_shutdown_callbacks_mutex_,
|
||||
pre_shutdown_callbacks_);
|
||||
} else {
|
||||
return remove_callback(on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
|
||||
return remove_callback(mutexStorage.getMutexes(this).on_shutdown_callbacks_mutex_,
|
||||
on_shutdown_callbacks_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,7 +528,7 @@ std::vector<rclcpp::Context::ShutdownCallback>
|
||||
Context::get_shutdown_callback() const
|
||||
{
|
||||
const auto get_callback_vector = [](auto & mutex, auto & callback_set) {
|
||||
const std::lock_guard<std::mutex> lock(mutex);
|
||||
const std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||
std::vector<rclcpp::Context::ShutdownCallback> callbacks;
|
||||
for (auto & callback : callback_set) {
|
||||
callbacks.push_back(*callback);
|
||||
@@ -474,9 +540,11 @@ Context::get_shutdown_callback() const
|
||||
shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
|
||||
|
||||
if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
|
||||
return get_callback_vector(pre_shutdown_callbacks_mutex_, pre_shutdown_callbacks_);
|
||||
return get_callback_vector(mutexStorage.getMutexes(this).pre_shutdown_callbacks_mutex_,
|
||||
pre_shutdown_callbacks_);
|
||||
} else {
|
||||
return get_callback_vector(on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
|
||||
return get_callback_vector(mutexStorage.getMutexes(this).on_shutdown_callbacks_mutex_,
|
||||
on_shutdown_callbacks_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -689,7 +689,7 @@ Node::create_generic_client(
|
||||
node_base_,
|
||||
node_graph_,
|
||||
node_services_,
|
||||
service_name,
|
||||
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
|
||||
service_type,
|
||||
qos,
|
||||
group);
|
||||
|
||||
@@ -1191,3 +1191,10 @@ NodeParameters::get_parameter_overrides() const
|
||||
{
|
||||
return parameter_overrides_;
|
||||
}
|
||||
|
||||
void
|
||||
NodeParameters::enable_parameter_modification()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
parameter_modification_enabled_ = true;
|
||||
}
|
||||
|
||||
@@ -65,11 +65,11 @@ public:
|
||||
: logger_(node_logging->get_logger()),
|
||||
node_base_(node_base)
|
||||
{
|
||||
rclcpp::ParameterValue enable_param;
|
||||
const std::string enable_param_name = "start_type_description_service";
|
||||
|
||||
bool enabled = false;
|
||||
try {
|
||||
auto enable_param = node_parameters->declare_parameter(
|
||||
if (!node_parameters->has_parameter(enable_param_name)) {
|
||||
enable_param = node_parameters->declare_parameter(
|
||||
enable_param_name,
|
||||
rclcpp::ParameterValue(true),
|
||||
rcl_interfaces::msg::ParameterDescriptor()
|
||||
@@ -77,13 +77,21 @@ public:
|
||||
.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;
|
||||
} else {
|
||||
enable_param = node_parameters->get_parameter(enable_param_name).get_parameter_value();
|
||||
}
|
||||
if (enable_param.get_type() != rclcpp::PARAMETER_BOOL) {
|
||||
RCLCPP_ERROR(
|
||||
logger_,
|
||||
"Invalid type '%s' for parameter 'start_type_description_service', should be 'bool'",
|
||||
rclcpp::to_string(enable_param.get_type()).c_str());
|
||||
std::ostringstream ss;
|
||||
ss << "Wrong parameter type, parameter {" << enable_param_name << "} is of type {bool}, "
|
||||
<< "setting it to {" << to_string(enable_param.get_type()) << "} is not allowed.";
|
||||
throw rclcpp::exceptions::InvalidParameterTypeException(enable_param_name, ss.str());
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
if (enable_param.get<bool>()) {
|
||||
auto * rcl_node = node_base->get_rcl_node_handle();
|
||||
std::shared_ptr<rcl_service_t> rcl_srv(
|
||||
new rcl_service_t,
|
||||
|
||||
@@ -28,6 +28,9 @@ ParameterEventsFilter::ParameterEventsFilter(
|
||||
const std::vector<EventType> & types)
|
||||
: event_(event)
|
||||
{
|
||||
if (!event) {
|
||||
throw std::invalid_argument("event cannot be null");
|
||||
}
|
||||
if (std::find(types.begin(), types.end(), EventType::NEW) != types.end()) {
|
||||
for (auto & new_parameter : event->new_parameters) {
|
||||
if (std::find(names.begin(), names.end(), new_parameter.name) != names.end()) {
|
||||
|
||||
@@ -81,7 +81,15 @@ rclcpp::parameter_map_from(const rcl_params_t * const c_params, const char * nod
|
||||
throw InvalidParametersException(message);
|
||||
}
|
||||
const rcl_variant_t * const c_param_value = &(c_params_node->parameter_values[p]);
|
||||
params_node.emplace_back(c_param_name, parameter_value_from(c_param_value));
|
||||
ParameterValue value;
|
||||
try {
|
||||
value = parameter_value_from(c_param_value);
|
||||
} catch (const InvalidParameterValueException & e) {
|
||||
throw InvalidParameterValueException(
|
||||
std::string("parameter_value_from failed for parameter '") +
|
||||
c_param_name + "': " + e.what());
|
||||
}
|
||||
params_node.emplace_back(c_param_name, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,8 +69,10 @@ QoSInitialization::from_rmw(const rmw_qos_profile_t & rmw_qos)
|
||||
return KeepLast(rmw_qos.depth, false);
|
||||
case RMW_QOS_POLICY_HISTORY_KEEP_LAST:
|
||||
case RMW_QOS_POLICY_HISTORY_UNKNOWN:
|
||||
default:
|
||||
return KeepLast(rmw_qos.depth);
|
||||
default:
|
||||
throw std::invalid_argument(
|
||||
"Invalid history policy enum value passed to QoSInitialization::from_rmw");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@ SerializationBase::SerializationBase(const rosidl_message_type_support_t * type_
|
||||
void SerializationBase::serialize_message(
|
||||
const void * ros_message, SerializedMessage * serialized_message) const
|
||||
{
|
||||
rcpputils::check_true(nullptr != type_support_, "Typesupport is nullpointer.");
|
||||
rcpputils::check_true(nullptr != ros_message, "ROS message is nullpointer.");
|
||||
rcpputils::check_true(nullptr != serialized_message, "Serialized message is nullpointer.");
|
||||
|
||||
@@ -52,7 +51,6 @@ void SerializationBase::serialize_message(
|
||||
void SerializationBase::deserialize_message(
|
||||
const SerializedMessage * serialized_message, void * ros_message) const
|
||||
{
|
||||
rcpputils::check_true(nullptr != type_support_, "Typesupport is nullpointer.");
|
||||
rcpputils::check_true(nullptr != serialized_message, "Serialized message is nullpointer.");
|
||||
rcpputils::check_true(
|
||||
0u != serialized_message->capacity(),
|
||||
|
||||
@@ -26,8 +26,13 @@ namespace rclcpp
|
||||
|
||||
inline void copy_rcl_message(const rcl_serialized_message_t & from, rcl_serialized_message_t & to)
|
||||
{
|
||||
const auto ret = rmw_serialized_message_init(
|
||||
&to, from.buffer_capacity, &from.allocator);
|
||||
auto ret = RCL_RET_ERROR;
|
||||
if (nullptr == to.buffer) {
|
||||
ret = rmw_serialized_message_init(&to, from.buffer_capacity, &from.allocator);
|
||||
} else {
|
||||
ret = rmw_serialized_message_resize(&to, from.buffer_capacity);
|
||||
}
|
||||
|
||||
if (RCL_RET_OK != ret) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret);
|
||||
}
|
||||
@@ -78,7 +83,6 @@ SerializedMessage::SerializedMessage(rcl_serialized_message_t && other)
|
||||
SerializedMessage & SerializedMessage::operator=(const SerializedMessage & other)
|
||||
{
|
||||
if (this != &other) {
|
||||
serialized_message_ = rmw_get_zero_initialized_serialized_message();
|
||||
copy_rcl_message(other.serialized_message_, serialized_message_);
|
||||
}
|
||||
|
||||
@@ -88,7 +92,6 @@ SerializedMessage & SerializedMessage::operator=(const SerializedMessage & other
|
||||
SerializedMessage & SerializedMessage::operator=(const rcl_serialized_message_t & other)
|
||||
{
|
||||
if (&serialized_message_ != &other) {
|
||||
serialized_message_ = rmw_get_zero_initialized_serialized_message();
|
||||
copy_rcl_message(other, serialized_message_);
|
||||
}
|
||||
|
||||
@@ -98,6 +101,14 @@ SerializedMessage & SerializedMessage::operator=(const rcl_serialized_message_t
|
||||
SerializedMessage & SerializedMessage::operator=(SerializedMessage && other)
|
||||
{
|
||||
if (this != &other) {
|
||||
if (nullptr != serialized_message_.buffer) {
|
||||
const auto fini_ret = rmw_serialized_message_fini(&serialized_message_);
|
||||
if (RCL_RET_OK != fini_ret) {
|
||||
RCLCPP_ERROR(
|
||||
get_logger("rclcpp"),
|
||||
"Failed to destroy serialized message: %s", rcl_get_error_string().str);
|
||||
}
|
||||
}
|
||||
serialized_message_ =
|
||||
std::exchange(other.serialized_message_, rmw_get_zero_initialized_serialized_message());
|
||||
}
|
||||
@@ -108,6 +119,14 @@ SerializedMessage & SerializedMessage::operator=(SerializedMessage && other)
|
||||
SerializedMessage & SerializedMessage::operator=(rcl_serialized_message_t && other)
|
||||
{
|
||||
if (&serialized_message_ != &other) {
|
||||
if (nullptr != serialized_message_.buffer) {
|
||||
const auto fini_ret = rmw_serialized_message_fini(&serialized_message_);
|
||||
if (RCL_RET_OK != fini_ret) {
|
||||
RCLCPP_ERROR(
|
||||
get_logger("rclcpp"),
|
||||
"Failed to destroy serialized message: %s", rcl_get_error_string().str);
|
||||
}
|
||||
}
|
||||
serialized_message_ =
|
||||
std::exchange(other, rmw_get_zero_initialized_serialized_message());
|
||||
}
|
||||
|
||||
@@ -276,13 +276,8 @@ public:
|
||||
on_set_parameters_callback_ = node_parameters_->add_on_set_parameters_callback(
|
||||
std::bind(&TimeSource::NodeState::on_set_parameters, this, std::placeholders::_1));
|
||||
|
||||
|
||||
// TODO(tfoote) use parameters interface not subscribe to events via topic ticketed #609
|
||||
parameter_subscription_ = rclcpp::AsyncParametersClient::on_parameter_event(
|
||||
node_topics_,
|
||||
[this](std::shared_ptr<const rcl_interfaces::msg::ParameterEvent> event) {
|
||||
this->on_parameter_event(event);
|
||||
});
|
||||
post_set_parameters_callback_ = node_parameters_->add_post_set_parameters_callback(
|
||||
std::bind(&TimeSource::NodeState::post_set_parameters, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
// Detach the attached node
|
||||
@@ -296,8 +291,11 @@ public:
|
||||
if (on_set_parameters_callback_) {
|
||||
node_parameters_->remove_on_set_parameters_callback(on_set_parameters_callback_.get());
|
||||
}
|
||||
if (post_set_parameters_callback_) {
|
||||
node_parameters_->remove_post_set_parameters_callback(post_set_parameters_callback_.get());
|
||||
}
|
||||
on_set_parameters_callback_.reset();
|
||||
parameter_subscription_.reset();
|
||||
post_set_parameters_callback_.reset();
|
||||
node_base_.reset();
|
||||
node_topics_.reset();
|
||||
node_graph_.reset();
|
||||
@@ -346,7 +344,6 @@ private:
|
||||
std::mutex clock_sub_lock_;
|
||||
rclcpp::CallbackGroup::SharedPtr clock_callback_group_;
|
||||
rclcpp::executors::SingleThreadedExecutor::SharedPtr clock_executor_;
|
||||
std::promise<void> cancel_clock_executor_promise_;
|
||||
|
||||
// The clock callback itself
|
||||
void clock_cb(std::shared_ptr<const rosgraph_msgs::msg::Clock> msg)
|
||||
@@ -392,12 +389,10 @@ private:
|
||||
clock_executor_ =
|
||||
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(exec_options);
|
||||
if (!clock_executor_thread_.joinable()) {
|
||||
cancel_clock_executor_promise_ = std::promise<void>{};
|
||||
clock_executor_thread_ = std::thread(
|
||||
[this]() {
|
||||
auto future = cancel_clock_executor_promise_.get_future();
|
||||
clock_executor_->add_callback_group(clock_callback_group_, node_base_);
|
||||
clock_executor_->spin_until_future_complete(future);
|
||||
clock_executor_->spin();
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -429,7 +424,6 @@ private:
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(clock_sub_lock_);
|
||||
if (clock_executor_thread_.joinable()) {
|
||||
cancel_clock_executor_promise_.set_value();
|
||||
clock_executor_->cancel();
|
||||
clock_executor_thread_.join();
|
||||
clock_executor_->remove_callback_group(clock_callback_group_);
|
||||
@@ -440,9 +434,9 @@ private:
|
||||
// On set Parameters callback handle
|
||||
node_interfaces::OnSetParametersCallbackHandle::SharedPtr on_set_parameters_callback_{nullptr};
|
||||
|
||||
// Parameter Event subscription
|
||||
using ParamSubscriptionT = rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>;
|
||||
std::shared_ptr<ParamSubscriptionT> parameter_subscription_;
|
||||
// Post set Parameters callback handle
|
||||
node_interfaces::PostSetParametersCallbackHandle::SharedPtr
|
||||
post_set_parameters_callback_{nullptr};
|
||||
|
||||
// Callback for parameter settings
|
||||
rcl_interfaces::msg::SetParametersResult on_set_parameters(
|
||||
@@ -465,52 +459,27 @@ private:
|
||||
return result;
|
||||
}
|
||||
|
||||
// Callback for parameter updates
|
||||
void on_parameter_event(std::shared_ptr<const rcl_interfaces::msg::ParameterEvent> event)
|
||||
// Callback for post parameter updates
|
||||
void post_set_parameters(const std::vector<rclcpp::Parameter> & parameters)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(node_base_lock_);
|
||||
|
||||
if (node_base_ == nullptr) {
|
||||
// Do nothing if node_base_ is nullptr because it means the TimeSource is now
|
||||
// without an attached node
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter out events on 'use_sim_time' parameter instances in other nodes.
|
||||
if (event->node != node_base_->get_fully_qualified_name()) {
|
||||
return;
|
||||
}
|
||||
// Filter for only 'use_sim_time' being added or changed.
|
||||
rclcpp::ParameterEventsFilter filter(event, {"use_sim_time"},
|
||||
{rclcpp::ParameterEventsFilter::EventType::NEW,
|
||||
rclcpp::ParameterEventsFilter::EventType::CHANGED});
|
||||
for (auto & it : filter.get_events()) {
|
||||
if (it.second->value.type != ParameterType::PARAMETER_BOOL) {
|
||||
RCLCPP_ERROR(logger_, "use_sim_time parameter cannot be set to anything but a bool");
|
||||
continue;
|
||||
// "use_sim_time" has been set, so just applys it to internal states
|
||||
for (const auto & param : parameters) {
|
||||
if (param.get_name() == "use_sim_time") {
|
||||
if (param.as_bool()) {
|
||||
parameter_state_ = SET_TRUE;
|
||||
clocks_state_.enable_ros_time();
|
||||
create_clock_sub();
|
||||
} else {
|
||||
parameter_state_ = SET_FALSE;
|
||||
destroy_clock_sub();
|
||||
clocks_state_.disable_ros_time();
|
||||
}
|
||||
}
|
||||
if (it.second->value.bool_value) {
|
||||
parameter_state_ = SET_TRUE;
|
||||
clocks_state_.enable_ros_time();
|
||||
create_clock_sub();
|
||||
} else {
|
||||
parameter_state_ = SET_FALSE;
|
||||
destroy_clock_sub();
|
||||
clocks_state_.disable_ros_time();
|
||||
}
|
||||
}
|
||||
// Handle the case that use_sim_time was deleted.
|
||||
rclcpp::ParameterEventsFilter deleted(event, {"use_sim_time"},
|
||||
{rclcpp::ParameterEventsFilter::EventType::DELETED});
|
||||
for (auto & it : deleted.get_events()) {
|
||||
(void) it; // if there is a match it's already matched, don't bother reading it.
|
||||
// If the parameter is deleted mark it as unset but don't change state.
|
||||
parameter_state_ = UNSET;
|
||||
}
|
||||
}
|
||||
|
||||
// An enum to hold the parameter state
|
||||
enum UseSimTimeParameterState {UNSET, SET_TRUE, SET_FALSE};
|
||||
enum UseSimTimeParameterState {SET_TRUE, SET_FALSE};
|
||||
UseSimTimeParameterState parameter_state_;
|
||||
};
|
||||
|
||||
|
||||
@@ -35,62 +35,6 @@ namespace rclcpp
|
||||
namespace
|
||||
{
|
||||
|
||||
// Look for the library in the ament prefix paths.
|
||||
std::string get_typesupport_library_path(
|
||||
const std::string & package_name, const std::string & typesupport_identifier)
|
||||
{
|
||||
const char * dynamic_library_folder;
|
||||
#ifdef _WIN32
|
||||
dynamic_library_folder = "/bin/";
|
||||
#elif __APPLE__
|
||||
dynamic_library_folder = "/lib/";
|
||||
#else
|
||||
dynamic_library_folder = "/lib/";
|
||||
#endif
|
||||
|
||||
std::string package_prefix;
|
||||
try {
|
||||
package_prefix = ament_index_cpp::get_package_prefix(package_name);
|
||||
} catch (ament_index_cpp::PackageNotFoundError & e) {
|
||||
throw std::runtime_error(e.what());
|
||||
}
|
||||
|
||||
const std::string library_path = rcpputils::path_for_library(
|
||||
package_prefix + dynamic_library_folder,
|
||||
package_name + "__" + typesupport_identifier);
|
||||
if (library_path.empty()) {
|
||||
throw std::runtime_error(
|
||||
"Typesupport library for " + package_name + " does not exist in '" + package_prefix +
|
||||
"'.");
|
||||
}
|
||||
return library_path;
|
||||
}
|
||||
|
||||
std::tuple<std::string, std::string, std::string>
|
||||
extract_type_identifier(const std::string & full_type)
|
||||
{
|
||||
char type_separator = '/';
|
||||
auto sep_position_back = full_type.find_last_of(type_separator);
|
||||
auto sep_position_front = full_type.find_first_of(type_separator);
|
||||
if (sep_position_back == std::string::npos ||
|
||||
sep_position_back == 0 ||
|
||||
sep_position_back == full_type.length() - 1)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Message type is not of the form package/type and cannot be processed");
|
||||
}
|
||||
|
||||
std::string package_name = full_type.substr(0, sep_position_front);
|
||||
std::string middle_module = "";
|
||||
if (sep_position_back - sep_position_front > 0) {
|
||||
middle_module =
|
||||
full_type.substr(sep_position_front + 1, sep_position_back - sep_position_front - 1);
|
||||
}
|
||||
std::string type_name = full_type.substr(sep_position_back + 1);
|
||||
|
||||
return std::make_tuple(package_name, middle_module, type_name);
|
||||
}
|
||||
|
||||
const void * get_typesupport_handle_impl(
|
||||
const std::string & type,
|
||||
const std::string & typesupport_identifier,
|
||||
@@ -131,6 +75,61 @@ const void * get_typesupport_handle_impl(
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
std::tuple<std::string, std::string, std::string>
|
||||
extract_type_identifier(const std::string & full_type)
|
||||
{
|
||||
char type_separator = '/';
|
||||
auto sep_position_back = full_type.find_last_of(type_separator);
|
||||
auto sep_position_front = full_type.find_first_of(type_separator);
|
||||
if (sep_position_back == std::string::npos ||
|
||||
sep_position_back == 0 ||
|
||||
sep_position_back == full_type.length() - 1)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Message type is not of the form package/type and cannot be processed");
|
||||
}
|
||||
|
||||
std::string package_name = full_type.substr(0, sep_position_front);
|
||||
std::string middle_module = "";
|
||||
if (sep_position_back - sep_position_front > 0) {
|
||||
middle_module =
|
||||
full_type.substr(sep_position_front + 1, sep_position_back - sep_position_front - 1);
|
||||
}
|
||||
std::string type_name = full_type.substr(sep_position_back + 1);
|
||||
|
||||
return std::make_tuple(package_name, middle_module, type_name);
|
||||
}
|
||||
|
||||
std::string get_typesupport_library_path(
|
||||
const std::string & package_name, const std::string & typesupport_identifier)
|
||||
{
|
||||
const char * dynamic_library_folder;
|
||||
#ifdef _WIN32
|
||||
dynamic_library_folder = "/bin/";
|
||||
#elif __APPLE__
|
||||
dynamic_library_folder = "/lib/";
|
||||
#else
|
||||
dynamic_library_folder = "/lib/";
|
||||
#endif
|
||||
|
||||
std::string package_prefix;
|
||||
try {
|
||||
package_prefix = ament_index_cpp::get_package_prefix(package_name);
|
||||
} catch (ament_index_cpp::PackageNotFoundError & e) {
|
||||
throw std::runtime_error(e.what());
|
||||
}
|
||||
|
||||
const std::string library_path = rcpputils::path_for_library(
|
||||
package_prefix + dynamic_library_folder,
|
||||
package_name + "__" + typesupport_identifier);
|
||||
if (library_path.empty()) {
|
||||
throw std::runtime_error(
|
||||
"Typesupport library for " + package_name + " does not exist in '" + package_prefix +
|
||||
"'.");
|
||||
}
|
||||
return library_path;
|
||||
}
|
||||
|
||||
std::shared_ptr<rcpputils::SharedLibrary>
|
||||
get_typesupport_library(const std::string & type, const std::string & typesupport_identifier)
|
||||
{
|
||||
@@ -139,14 +138,6 @@ get_typesupport_library(const std::string & type, const std::string & typesuppor
|
||||
return std::make_shared<rcpputils::SharedLibrary>(library_path);
|
||||
}
|
||||
|
||||
const rosidl_message_type_support_t * get_typesupport_handle(
|
||||
const std::string & type,
|
||||
const std::string & typesupport_identifier,
|
||||
rcpputils::SharedLibrary & library)
|
||||
{
|
||||
return get_message_typesupport_handle(type, typesupport_identifier, library);
|
||||
}
|
||||
|
||||
const rosidl_message_type_support_t * get_message_typesupport_handle(
|
||||
const std::string & type,
|
||||
const std::string & typesupport_identifier,
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
@@ -196,7 +196,7 @@ ament_add_gtest(test_node_interfaces__node_parameters
|
||||
node_interfaces/test_node_parameters.cpp)
|
||||
ament_add_test_label(test_node_interfaces__node_parameters mimick)
|
||||
if(TARGET test_node_interfaces__node_parameters)
|
||||
target_link_libraries(test_node_interfaces__node_parameters ${PROJECT_NAME} mimick rcpputils::rcpputils)
|
||||
target_link_libraries(test_node_interfaces__node_parameters ${PROJECT_NAME} mimick rcpputils::rcpputils ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_node_interfaces__node_services
|
||||
node_interfaces/test_node_services.cpp)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/experimental/executors/events_executor/events_executor_event_types.hpp"
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/node_interfaces/node_parameters.hpp"
|
||||
|
||||
#include "test_msgs/msg/empty.hpp"
|
||||
|
||||
#include "../../mocking_utils/patch.hpp"
|
||||
#include "../../utils/rclcpp_gtest_macros.hpp"
|
||||
|
||||
@@ -126,7 +128,7 @@ TEST_F(TestNodeParameters, list_parameters)
|
||||
list_result5.names.end());
|
||||
}
|
||||
|
||||
TEST_F(TestNodeParameters, parameter_overrides)
|
||||
TEST_F(TestNodeParameters, parameter_overrides_with_value)
|
||||
{
|
||||
rclcpp::NodeOptions node_options;
|
||||
node_options.automatically_declare_parameters_from_overrides(true);
|
||||
@@ -144,6 +146,24 @@ TEST_F(TestNodeParameters, parameter_overrides)
|
||||
EXPECT_EQ(2u, parameter_overrides.size());
|
||||
}
|
||||
|
||||
TEST_F(TestNodeParameters, parameter_overrides_with_parameter)
|
||||
{
|
||||
rclcpp::NodeOptions node_options;
|
||||
node_options.automatically_declare_parameters_from_overrides(true);
|
||||
node_options.append_parameter_override(rclcpp::Parameter("param1", true));
|
||||
node_options.append_parameter_override(rclcpp::Parameter("param2", 42));
|
||||
|
||||
std::shared_ptr<rclcpp::Node> node2 = std::make_shared<rclcpp::Node>("node2", "ns", node_options);
|
||||
|
||||
auto * node_parameters_interface =
|
||||
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
|
||||
node2->get_node_parameters_interface().get());
|
||||
ASSERT_NE(nullptr, node_parameters_interface);
|
||||
|
||||
const auto & parameter_overrides = node_parameters_interface->get_parameter_overrides();
|
||||
EXPECT_EQ(2u, parameter_overrides.size());
|
||||
}
|
||||
|
||||
TEST_F(TestNodeParameters, set_parameters) {
|
||||
rclcpp::NodeOptions node_options;
|
||||
node_options.allow_undeclared_parameters(true);
|
||||
@@ -329,6 +349,89 @@ TEST_F(TestNodeParameters, add_remove_post_set_parameters_callback) {
|
||||
std::runtime_error("Post set parameter callback doesn't exist"));
|
||||
}
|
||||
|
||||
TEST_F(TestNodeParameters, set_param_recursive_in_post_set_parameters_callback) {
|
||||
rclcpp::Subscription<test_msgs::msg::Empty>::SharedPtr subscription_;
|
||||
rclcpp::Publisher<test_msgs::msg::Empty>::SharedPtr publisher_;
|
||||
|
||||
rcl_interfaces::msg::ParameterDescriptor param_descriptor;
|
||||
param_descriptor.name = "create_entities";
|
||||
param_descriptor.type = rcl_interfaces::msg::ParameterType::PARAMETER_BOOL;
|
||||
param_descriptor.read_only = false;
|
||||
|
||||
bool result = node_parameters->declare_parameter(
|
||||
"create_entities", rclcpp::ParameterValue(false), param_descriptor, false).get<bool>();
|
||||
EXPECT_EQ(result, false);
|
||||
|
||||
// Register a callback to create/delete publisher and subscription with
|
||||
// QoS override parameter options. This will call declare_parameter recursively
|
||||
// during this callback.
|
||||
auto sub_callback = [](test_msgs::msg::Empty::ConstSharedPtr) {};
|
||||
auto callback = [&](const std::vector<rclcpp::Parameter> & parameters) {
|
||||
for (const auto & parameter : parameters) {
|
||||
if (parameter.get_name() == "create_entities" &&
|
||||
parameter.get_type() == rclcpp::ParameterType::PARAMETER_BOOL)
|
||||
{
|
||||
if (parameter.as_bool()) {
|
||||
ASSERT_EQ(subscription_, nullptr);
|
||||
rclcpp::SubscriptionOptions sub_options;
|
||||
// This will declare the QoS override parameters in this callback.
|
||||
sub_options.qos_overriding_options =
|
||||
rclcpp::QosOverridingOptions::with_default_policies();
|
||||
subscription_ = node->create_subscription<test_msgs::msg::Empty>(
|
||||
"empty",
|
||||
rclcpp::QoS(10),
|
||||
sub_callback,
|
||||
sub_options);
|
||||
ASSERT_NE(subscription_, nullptr);
|
||||
ASSERT_EQ(publisher_, nullptr);
|
||||
rclcpp::PublisherOptions pub_options;
|
||||
// This will declare the QoS override parameters in this callback.
|
||||
pub_options.qos_overriding_options =
|
||||
rclcpp::QosOverridingOptions::with_default_policies();
|
||||
publisher_ = node->create_publisher<test_msgs::msg::Empty>(
|
||||
"empty",
|
||||
rclcpp::QoS(10),
|
||||
pub_options);
|
||||
ASSERT_NE(publisher_, nullptr);
|
||||
} else {
|
||||
ASSERT_NE(subscription_, nullptr);
|
||||
subscription_.reset();
|
||||
ASSERT_EQ(subscription_, nullptr);
|
||||
ASSERT_NE(publisher_, nullptr);
|
||||
publisher_.reset();
|
||||
ASSERT_EQ(publisher_, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto handle = node_parameters->add_post_set_parameters_callback(callback);
|
||||
ASSERT_NE(handle, nullptr);
|
||||
EXPECT_TRUE(node_parameters->has_parameter("create_entities"));
|
||||
EXPECT_EQ(node_parameters->get_parameter("create_entities").get_value<bool>(), false);
|
||||
|
||||
// This will call the registered callback, that will create endpoints with
|
||||
// declaring the QoS override parameters recursively.
|
||||
auto results = node_parameters->set_parameters({rclcpp::Parameter("create_entities", true)});
|
||||
EXPECT_TRUE(!results.empty() && results[0].successful);
|
||||
|
||||
EXPECT_TRUE(node_parameters->has_parameter("create_entities"));
|
||||
EXPECT_EQ(node_parameters->get_parameter("create_entities").get_value<bool>(), true);
|
||||
|
||||
// Destroy publisher and subscription endpoints.
|
||||
results = node_parameters->set_parameters({rclcpp::Parameter("create_entities", false)});
|
||||
EXPECT_TRUE(!results.empty() && results[0].successful);
|
||||
|
||||
EXPECT_TRUE(node_parameters->has_parameter("create_entities"));
|
||||
EXPECT_EQ(node_parameters->get_parameter("create_entities").get_value<bool>(), false);
|
||||
|
||||
// Make sure recreation can also work without any exception.
|
||||
results = node_parameters->set_parameters({rclcpp::Parameter("create_entities", true)});
|
||||
EXPECT_TRUE(!results.empty() && results[0].successful);
|
||||
|
||||
EXPECT_NO_THROW(node_parameters->remove_post_set_parameters_callback(handle.get()));
|
||||
}
|
||||
|
||||
TEST_F(TestNodeParameters, wildcard_with_namespace)
|
||||
{
|
||||
rclcpp::NodeOptions opts;
|
||||
|
||||
@@ -37,6 +37,38 @@ TEST_F(TestNodeTypeDescriptions, interface_created)
|
||||
ASSERT_NE(nullptr, node.get_node_type_descriptions_interface());
|
||||
}
|
||||
|
||||
TEST_F(TestNodeTypeDescriptions, automatically_declare_parameters_from_overrides)
|
||||
{
|
||||
rclcpp::NodeOptions node_options;
|
||||
node_options.automatically_declare_parameters_from_overrides(true);
|
||||
node_options.append_parameter_override("start_type_description_service", false);
|
||||
ASSERT_NO_THROW(
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns", node_options);
|
||||
(void) node;
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(TestNodeTypeDescriptions, bad_parameter_type)
|
||||
{
|
||||
rclcpp::NodeOptions node_options;
|
||||
node_options.append_parameter_override("start_type_description_service", "unexpected_type");
|
||||
|
||||
ASSERT_THROW(
|
||||
{
|
||||
node_options.automatically_declare_parameters_from_overrides(false);
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns", node_options);
|
||||
(void) node;
|
||||
}, rclcpp::exceptions::InvalidParameterTypeException);
|
||||
|
||||
ASSERT_THROW(
|
||||
{
|
||||
node_options.automatically_declare_parameters_from_overrides(true);
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns", node_options);
|
||||
(void) node;
|
||||
}, rclcpp::exceptions::InvalidParameterTypeException);
|
||||
}
|
||||
|
||||
TEST_F(TestNodeTypeDescriptions, disabled_no_service)
|
||||
{
|
||||
rclcpp::NodeOptions node_options;
|
||||
|
||||
@@ -184,7 +184,10 @@ TEST_F(TestClockWakeup, no_wakeup_on_sim_time) {
|
||||
TEST_F(TestClockWakeup, multiple_threads_wait_on_one_clock) {
|
||||
auto clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
|
||||
|
||||
std::vector<bool> thread_finished(10, false);
|
||||
std::vector<std::atomic_bool> thread_finished(10);
|
||||
for (std::atomic_bool & finished : thread_finished) {
|
||||
finished = false;
|
||||
}
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
@@ -202,7 +205,7 @@ TEST_F(TestClockWakeup, multiple_threads_wait_on_one_clock) {
|
||||
// wait a bit so all threads can execute the sleep_until
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
|
||||
for (const bool & finished : thread_finished) {
|
||||
for (const std::atomic_bool & finished : thread_finished) {
|
||||
EXPECT_FALSE(finished);
|
||||
}
|
||||
|
||||
@@ -213,7 +216,7 @@ TEST_F(TestClockWakeup, multiple_threads_wait_on_one_clock) {
|
||||
bool threads_finished = false;
|
||||
while (!threads_finished && start_time + std::chrono::seconds(1) > cur_time) {
|
||||
threads_finished = true;
|
||||
for (const bool finished : thread_finished) {
|
||||
for (const std::atomic_bool & finished : thread_finished) {
|
||||
if (!finished) {
|
||||
threads_finished = false;
|
||||
}
|
||||
@@ -223,7 +226,7 @@ TEST_F(TestClockWakeup, multiple_threads_wait_on_one_clock) {
|
||||
cur_time = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
for (const bool finished : thread_finished) {
|
||||
for (const std::atomic_bool & finished : thread_finished) {
|
||||
EXPECT_TRUE(finished);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,11 +19,16 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "rcl_interfaces/msg/parameter_event.hpp"
|
||||
|
||||
#include "rclcpp/executor.hpp"
|
||||
#include "rclcpp/memory_strategy.hpp"
|
||||
#include "rclcpp/executors/single_threaded_executor.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "rclcpp/strategies/allocator_memory_strategy.hpp"
|
||||
|
||||
#include "test_msgs/msg/empty.hpp"
|
||||
|
||||
#include "../mocking_utils/patch.hpp"
|
||||
#include "../utils/rclcpp_gtest_macros.hpp"
|
||||
|
||||
@@ -331,8 +336,17 @@ TEST_F(TestExecutor, spin_all_fail_wait_set_clear) {
|
||||
node->create_wall_timer(std::chrono::milliseconds(1), [&]() {});
|
||||
|
||||
dummy.add_node(node);
|
||||
auto callback = [](test_msgs::msg::Empty::ConstSharedPtr) {};
|
||||
rclcpp::Subscription<test_msgs::msg::Empty>::SharedPtr subscription;
|
||||
auto node_topics = node->get_node_topics_interface();
|
||||
subscription =
|
||||
rclcpp::create_subscription<test_msgs::msg::Empty>(
|
||||
node_topics, "test", rclcpp::QoS(10), std::move(callback));
|
||||
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_wait_set_clear, RCL_RET_ERROR);
|
||||
|
||||
dummy.spin_all(std::chrono::milliseconds(1));
|
||||
// second spin_all triggers rcl_wait_set_clear that should be called
|
||||
// whenever a waitset gets rebuild and it was not changed in size.
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
dummy.spin_all(std::chrono::milliseconds(1)),
|
||||
std::runtime_error("Couldn't clear the wait set: error not set"));
|
||||
@@ -354,8 +368,14 @@ TEST_F(TestExecutor, spin_some_fail_wait_set_resize) {
|
||||
TEST_F(TestExecutor, spin_some_fail_add_handles_to_wait_set) {
|
||||
DummyExecutor dummy;
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
auto timer =
|
||||
node->create_wall_timer(std::chrono::milliseconds(1), [&]() {});
|
||||
|
||||
// create subscription explicitly, because we do not create subscription
|
||||
// on /parameter_events for 'use_sim_time' parameter anymore.
|
||||
auto callback = [](test_msgs::msg::Empty::ConstSharedPtr) {};
|
||||
rclcpp::Subscription<test_msgs::msg::Empty>::SharedPtr subscription;
|
||||
subscription =
|
||||
node->create_subscription<test_msgs::msg::Empty>(
|
||||
"test", rclcpp::QoS(10), std::move(callback));
|
||||
|
||||
dummy.add_node(node);
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
|
||||
@@ -221,7 +221,7 @@ TEST_F(TestGenericClient, wait_for_service) {
|
||||
TEST_F(TestGenericClientSub, construction_and_destruction) {
|
||||
{
|
||||
auto client = subnode->create_generic_client("test_service", "test_msgs/srv/Empty");
|
||||
EXPECT_STREQ(client->get_service_name(), "/ns/test_service");
|
||||
EXPECT_STREQ(client->get_service_name(), "/ns/sub_ns/test_service");
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -253,9 +253,19 @@ bool log_function_const_ref(const rclcpp::Logger & logger)
|
||||
return true;
|
||||
}
|
||||
|
||||
class DerivedLogger : public rclcpp::Logger
|
||||
{
|
||||
public:
|
||||
explicit DerivedLogger(const rclcpp::Logger & logger)
|
||||
: rclcpp::Logger(logger) {}
|
||||
};
|
||||
|
||||
TEST_F(TestLoggingMacros, test_log_from_node) {
|
||||
auto logger = rclcpp::get_logger("test_logging_logger");
|
||||
EXPECT_TRUE(log_function(logger));
|
||||
EXPECT_TRUE(log_function_const(logger));
|
||||
EXPECT_TRUE(log_function_const_ref(logger));
|
||||
|
||||
DerivedLogger derived_logger(logger);
|
||||
RCLCPP_INFO(derived_logger, "successful log from derived logger");
|
||||
}
|
||||
|
||||
@@ -306,6 +306,39 @@ TEST_F(TestNode, subnode_get_name_and_namespace) {
|
||||
}, rclcpp::exceptions::NameValidationError);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestNode, subnode_parameter_operation) {
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "ns");
|
||||
auto subnode = node->create_sub_node("sub_ns");
|
||||
|
||||
auto value = subnode->declare_parameter("param", 5);
|
||||
EXPECT_EQ(value, 5);
|
||||
// node and sub-node shares NodeParametersInterface, so expecting the exception.
|
||||
EXPECT_THROW(
|
||||
node->declare_parameter("param", 0),
|
||||
rclcpp::exceptions::ParameterAlreadyDeclaredException);
|
||||
rclcpp::Parameter param;
|
||||
|
||||
node->get_parameter("param", param);
|
||||
EXPECT_EQ(param.get_value<int>(), 5);
|
||||
subnode->get_parameter("param", param);
|
||||
EXPECT_EQ(param.get_value<int>(), 5);
|
||||
|
||||
int param_int;
|
||||
node->get_parameter("param", param_int);
|
||||
EXPECT_EQ(param_int, 5);
|
||||
subnode->get_parameter("param", param_int);
|
||||
EXPECT_EQ(param_int, 5);
|
||||
|
||||
EXPECT_EQ(node->get_parameter_or("param", 333), 5);
|
||||
EXPECT_EQ(subnode->get_parameter_or("param", 666), 5);
|
||||
|
||||
node->get_parameter_or("param", param_int, 333);
|
||||
EXPECT_EQ(param_int, 5);
|
||||
subnode->get_parameter_or("param", param_int, 666);
|
||||
EXPECT_EQ(param_int, 5);
|
||||
}
|
||||
|
||||
/*
|
||||
Testing node construction and destruction.
|
||||
*/
|
||||
|
||||
@@ -258,8 +258,10 @@ TEST(TestNodeOptions, append_parameter_override) {
|
||||
auto options = rclcpp::NodeOptions().arguments(expected_args).use_global_arguments(false);
|
||||
rclcpp::Parameter parameter("some_parameter", 10);
|
||||
options.append_parameter_override("some_parameter", 10);
|
||||
EXPECT_EQ(1u, options.parameter_overrides().size());
|
||||
options.append_parameter_override(parameter);
|
||||
EXPECT_EQ(2u, options.parameter_overrides().size());
|
||||
EXPECT_EQ(std::string("some_parameter"), options.parameter_overrides()[0].get_name());
|
||||
EXPECT_EQ(std::string("some_parameter"), options.parameter_overrides()[1].get_name());
|
||||
}
|
||||
|
||||
TEST(TestNodeOptions, rcl_node_options_fini_error) {
|
||||
|
||||
@@ -72,6 +72,13 @@ protected:
|
||||
/*
|
||||
Testing filters.
|
||||
*/
|
||||
TEST_F(TestParameterEventFilter, invalide_arguments) {
|
||||
EXPECT_THROW(
|
||||
rclcpp::ParameterEventsFilter(nullptr, {"new"}, {nt}),
|
||||
std::invalid_argument
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(TestParameterEventFilter, full_by_type) {
|
||||
auto res = rclcpp::ParameterEventsFilter(
|
||||
full,
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
@@ -199,7 +199,7 @@ TEST_F(TestPublisher, test_publisher_with_system_default_qos) {
|
||||
using test_msgs::msg::Empty;
|
||||
ASSERT_NO_THROW(
|
||||
{
|
||||
auto publisher = node->create_publisher<Empty>("topic", rclcpp::SystemDefaultsQoS());
|
||||
auto publisher = node->create_publisher<Empty>("topic", rclcpp::SystemDefaultsQoS(), options);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -272,3 +272,15 @@ TEST(TestQoS, qos_check_compatible)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestQoS, from_rmw_validity)
|
||||
{
|
||||
rmw_qos_profile_t invalid_qos;
|
||||
memset(&invalid_qos, 0, sizeof(invalid_qos));
|
||||
unsigned int n = 999;
|
||||
memcpy(&invalid_qos.history, &n, sizeof(n));
|
||||
|
||||
EXPECT_THROW({
|
||||
rclcpp::QoSInitialization::from_rmw(invalid_qos);
|
||||
}, std::invalid_argument);
|
||||
}
|
||||
|
||||
@@ -139,3 +139,15 @@ TEST(TestRingBufferImplementation, basic_usage_unique_ptr) {
|
||||
EXPECT_EQ(false, rb.has_data());
|
||||
EXPECT_EQ(false, rb.is_full());
|
||||
}
|
||||
|
||||
TEST(TestRingBufferImplementation, handle_nullptr_deletion) {
|
||||
rclcpp::experimental::buffers::RingBufferImplementation<std::unique_ptr<int>> rb(3);
|
||||
rb.enqueue(std::make_unique<int>(42));
|
||||
rb.enqueue(nullptr); // intentionally enqueuing nullptr
|
||||
rb.enqueue(std::make_unique<int>(84));
|
||||
auto all_data = rb.get_all_data();
|
||||
EXPECT_EQ(3u, all_data.size());
|
||||
EXPECT_EQ(42, *(all_data[0]));
|
||||
EXPECT_EQ(nullptr, all_data[1]);
|
||||
EXPECT_EQ(84, *(all_data[2]));
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <rcl/service_introspection.h>
|
||||
#include <rmw/rmw.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -107,3 +108,29 @@ TEST(TestUtilities, wait_for_message_twice_one_sub) {
|
||||
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
TEST(TestUtilities, wait_for_last_message) {
|
||||
rclcpp::init(0, nullptr);
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("wait_for_last_message_node");
|
||||
auto qos = rclcpp::QoS(1).reliable().transient_local();
|
||||
|
||||
using MsgT = test_msgs::msg::Strings;
|
||||
auto pub = node->create_publisher<MsgT>("wait_for_last_message_topic", qos);
|
||||
pub->publish(*get_messages_strings()[0]);
|
||||
|
||||
MsgT out;
|
||||
auto received = false;
|
||||
auto wait = std::async(
|
||||
[&]() {
|
||||
auto ret = rclcpp::wait_for_message(out, node, "wait_for_last_message_topic", 5s, qos);
|
||||
EXPECT_TRUE(ret);
|
||||
received = true;
|
||||
});
|
||||
|
||||
ASSERT_NO_THROW(wait.get());
|
||||
ASSERT_TRUE(received);
|
||||
EXPECT_EQ(out, *get_messages_strings()[0]);
|
||||
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,25 @@ Changelog for package rclcpp_action
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
29.5.3 (2025-09-11)
|
||||
-------------------
|
||||
* fix cmake deprecation (`#2914 <https://github.com/ros2/rclcpp/issues/2914>`_) (`#2915 <https://github.com/ros2/rclcpp/issues/2915>`_)
|
||||
* Contributors: mergify[bot]
|
||||
|
||||
29.5.2 (2025-07-07)
|
||||
-------------------
|
||||
|
||||
29.5.1 (2025-06-23)
|
||||
-------------------
|
||||
* Replace std::default_random_engine with std::mt19937 (rolling) (`#2843 <https://github.com/ros2/rclcpp/issues/2843>`_) (`#2866 <https://github.com/ros2/rclcpp/issues/2866>`_)
|
||||
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_) (`#2855 <https://github.com/ros2/rclcpp/issues/2855>`_)
|
||||
* Contributors: mergify[bot]
|
||||
|
||||
29.5.0 (2025-04-18)
|
||||
-------------------
|
||||
* Use std::recursive_mutex for action requests. (`#2798 <https://github.com/ros2/rclcpp/issues/2798>`_)
|
||||
* Contributors: Tomoya Fujita
|
||||
|
||||
29.4.0 (2025-04-04)
|
||||
-------------------
|
||||
* Remove warning (`#2790 <https://github.com/ros2/rclcpp/issues/2790>`_)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(rclcpp_action)
|
||||
|
||||
|
||||
@@ -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>29.4.0</version>
|
||||
<version>29.5.3</version>
|
||||
<description>Adds action APIs for C++.</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -172,16 +172,16 @@ public:
|
||||
using ResponseCallback = std::function<void (std::shared_ptr<void> response)>;
|
||||
|
||||
std::map<int64_t, ResponseCallback> pending_goal_responses;
|
||||
std::mutex goal_requests_mutex;
|
||||
std::recursive_mutex goal_requests_mutex;
|
||||
|
||||
std::map<int64_t, ResponseCallback> pending_result_responses;
|
||||
std::mutex result_requests_mutex;
|
||||
std::recursive_mutex result_requests_mutex;
|
||||
|
||||
std::map<int64_t, ResponseCallback> pending_cancel_responses;
|
||||
std::mutex cancel_requests_mutex;
|
||||
std::recursive_mutex cancel_requests_mutex;
|
||||
|
||||
std::independent_bits_engine<
|
||||
std::default_random_engine, 8, unsigned int> random_bytes_generator;
|
||||
std::mt19937, 8, unsigned int> random_bytes_generator;
|
||||
};
|
||||
|
||||
ClientBase::ClientBase(
|
||||
@@ -386,7 +386,7 @@ ClientBase::handle_goal_response(
|
||||
const rmw_request_id_t & response_header,
|
||||
std::shared_ptr<void> response)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(pimpl_->goal_requests_mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard(pimpl_->goal_requests_mutex);
|
||||
const int64_t & sequence_number = response_header.sequence_number;
|
||||
if (pimpl_->pending_goal_responses.count(sequence_number) == 0) {
|
||||
RCLCPP_ERROR(pimpl_->logger, "unknown goal response, ignoring...");
|
||||
@@ -399,7 +399,7 @@ ClientBase::handle_goal_response(
|
||||
void
|
||||
ClientBase::send_goal_request(std::shared_ptr<void> request, ResponseCallback callback)
|
||||
{
|
||||
std::unique_lock<std::mutex> guard(pimpl_->goal_requests_mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard(pimpl_->goal_requests_mutex);
|
||||
int64_t sequence_number;
|
||||
rcl_ret_t ret = rcl_action_send_goal_request(
|
||||
pimpl_->client_handle.get(), request.get(), &sequence_number);
|
||||
@@ -417,7 +417,7 @@ ClientBase::handle_result_response(
|
||||
{
|
||||
std::map<int64_t, ResponseCallback>::node_type pending_result_response;
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(pimpl_->result_requests_mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard(pimpl_->result_requests_mutex);
|
||||
const int64_t & sequence_number = response_header.sequence_number;
|
||||
if (pimpl_->pending_result_responses.count(sequence_number) == 0) {
|
||||
RCLCPP_ERROR(pimpl_->logger, "unknown result response, ignoring...");
|
||||
@@ -433,7 +433,7 @@ ClientBase::handle_result_response(
|
||||
void
|
||||
ClientBase::send_result_request(std::shared_ptr<void> request, ResponseCallback callback)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(pimpl_->result_requests_mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard(pimpl_->result_requests_mutex);
|
||||
int64_t sequence_number;
|
||||
rcl_ret_t ret = rcl_action_send_result_request(
|
||||
pimpl_->client_handle.get(), request.get(), &sequence_number);
|
||||
@@ -449,7 +449,7 @@ ClientBase::handle_cancel_response(
|
||||
const rmw_request_id_t & response_header,
|
||||
std::shared_ptr<void> response)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(pimpl_->cancel_requests_mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard(pimpl_->cancel_requests_mutex);
|
||||
const int64_t & sequence_number = response_header.sequence_number;
|
||||
if (pimpl_->pending_cancel_responses.count(sequence_number) == 0) {
|
||||
RCLCPP_ERROR(pimpl_->logger, "unknown cancel response, ignoring...");
|
||||
@@ -462,7 +462,7 @@ ClientBase::handle_cancel_response(
|
||||
void
|
||||
ClientBase::send_cancel_request(std::shared_ptr<void> request, ResponseCallback callback)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(pimpl_->cancel_requests_mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard(pimpl_->cancel_requests_mutex);
|
||||
int64_t sequence_number;
|
||||
rcl_ret_t ret = rcl_action_send_cancel_request(
|
||||
pimpl_->client_handle.get(), request.get(), &sequence_number);
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ TEST(TestActionTypes, goal_uuid_to_hashed_uuid_random) {
|
||||
// Use std::random_device to seed the generator of goal IDs.
|
||||
std::random_device rd;
|
||||
std::independent_bits_engine<
|
||||
std::default_random_engine, 8, decltype(rd())> random_bytes_generator(rd());
|
||||
std::mt19937, 8, decltype(rd())> random_bytes_generator(rd());
|
||||
|
||||
std::vector<size_t> hashed_guuids;
|
||||
constexpr size_t iterations = 1000;
|
||||
|
||||
@@ -2,6 +2,22 @@
|
||||
Changelog for package rclcpp_components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
29.5.3 (2025-09-11)
|
||||
-------------------
|
||||
* fix cmake deprecation (`#2914 <https://github.com/ros2/rclcpp/issues/2914>`_) (`#2915 <https://github.com/ros2/rclcpp/issues/2915>`_)
|
||||
* Contributors: mergify[bot]
|
||||
|
||||
29.5.2 (2025-07-07)
|
||||
-------------------
|
||||
|
||||
29.5.1 (2025-06-23)
|
||||
-------------------
|
||||
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_) (`#2855 <https://github.com/ros2/rclcpp/issues/2855>`_)
|
||||
* Contributors: mergify[bot]
|
||||
|
||||
29.5.0 (2025-04-18)
|
||||
-------------------
|
||||
|
||||
29.4.0 (2025-04-04)
|
||||
-------------------
|
||||
* Removed trailing whitespace from the codebase. (`#2791 <https://github.com/ros2/rclcpp/issues/2791>`_)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(rclcpp_components)
|
||||
|
||||
|
||||
@@ -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>29.4.0</version>
|
||||
<version>29.5.3</version>
|
||||
<description>Package containing tools for dynamically loadable components</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -3,6 +3,23 @@ Changelog for package rclcpp_lifecycle
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
29.5.3 (2025-09-11)
|
||||
-------------------
|
||||
* Clearer warning message, the old one lacked information and was perhaps misleading (`#2927 <https://github.com/ros2/rclcpp/issues/2927>`_) (`#2931 <https://github.com/ros2/rclcpp/issues/2931>`_)
|
||||
* fix cmake deprecation (`#2914 <https://github.com/ros2/rclcpp/issues/2914>`_) (`#2915 <https://github.com/ros2/rclcpp/issues/2915>`_)
|
||||
* Contributors: mergify[bot]
|
||||
|
||||
29.5.2 (2025-07-07)
|
||||
-------------------
|
||||
|
||||
29.5.1 (2025-06-23)
|
||||
-------------------
|
||||
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_) (`#2855 <https://github.com/ros2/rclcpp/issues/2855>`_)
|
||||
* Contributors: mergify[bot]
|
||||
|
||||
29.5.0 (2025-04-18)
|
||||
-------------------
|
||||
|
||||
29.4.0 (2025-04-04)
|
||||
-------------------
|
||||
* should pull valid transition before trying to change the state. (`#2774 <https://github.com/ros2/rclcpp/issues/2774>`_)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(rclcpp_lifecycle)
|
||||
|
||||
|
||||
@@ -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>29.4.0</version>
|
||||
<version>29.5.3</version>
|
||||
<description>Package containing a prototype for lifecycle implementation</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -390,6 +390,7 @@ LifecycleNode::LifecycleNodeInterfaceImpl::change_state(
|
||||
constexpr bool publish_update = true;
|
||||
State initial_state;
|
||||
unsigned int current_state_id;
|
||||
const rcl_lifecycle_transition_t * original_transition{nullptr};
|
||||
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(state_machine_mutex_);
|
||||
@@ -405,6 +406,10 @@ LifecycleNode::LifecycleNodeInterfaceImpl::change_state(
|
||||
// keep the initial state to pass to a transition callback
|
||||
initial_state = State(state_machine_.current_state);
|
||||
|
||||
original_transition =
|
||||
rcl_lifecycle_get_transition_by_id(state_machine_.current_state, transition_id);
|
||||
|
||||
|
||||
if (
|
||||
rcl_lifecycle_trigger_transition_by_id(
|
||||
&state_machine_, transition_id, publish_update) != RCL_RET_OK)
|
||||
@@ -455,12 +460,15 @@ LifecycleNode::LifecycleNodeInterfaceImpl::change_state(
|
||||
// Update the internal current_state_
|
||||
current_state_ = State(state_machine_.current_state);
|
||||
|
||||
// error handling ?!
|
||||
// error handling
|
||||
// TODO(karsten1987): iterate over possible ret value
|
||||
if (cb_return_code == node_interfaces::LifecycleNodeInterface::CallbackReturn::ERROR) {
|
||||
RCLCPP_WARN(
|
||||
node_logging_interface_->get_logger(),
|
||||
"Error occurred while doing error handling.");
|
||||
if (original_transition) {
|
||||
RCLCPP_WARN(
|
||||
node_logging_interface_->get_logger(),
|
||||
"Callback returned ERROR during the transition: %s", original_transition->label);
|
||||
}
|
||||
|
||||
|
||||
auto error_cb_code = execute_callback(current_state_id, initial_state);
|
||||
auto error_cb_label = get_label_for_return_code(error_cb_code);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
Reference in New Issue
Block a user