Compare commits

..

26 Commits

Author SHA1 Message Date
Yadunund
7907b2fee0 21.0.5 2024-02-07 17:29:33 +08:00
Yadunund
0dc2756dce Update changelogs
Signed-off-by: Yadunund <yadunund@openrobotics.org>
2024-02-07 17:29:13 +08:00
mergify[bot]
7877358e7b Fix data race in EventHandlerBase (#2349) (#2387)
Both the EventHandler and its associated pubs/subs share
the same underlying rmw event listener.
When a pub/sub is destroyed, the listener is destroyed.
There is a data race when the ~EventHandlerBase wants
to access the listener after it has been destroyed.

The EventHandler stores a shared_ptr of its associated pub/sub.
But since we were clearing the listener event callbacks on the
base class destructor ~EventHandlerBase, the pub/sub was
already destroyed, which means the rmw event listener was also
destroyed, thus causing a segfault when trying to obtain it
to clear the callbacks.

Clearing the callbacks on ~EventHandler instead of
~EventHandlerBase avoids the race, since the pub/sub are still valid.

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>
(cherry picked from commit 411dbe8212)

Co-authored-by: mauropasse <mauropasse@hotmail.com>
2023-12-13 10:13:25 -08:00
mergify[bot]
dc6ac4e30f fix(rclcpp_components): increase the service queue sizes in component_container (#2363) (#2381)
* fix(rclcpp_components): increase the service queue sizes in component_container

Signed-off-by: M. Fatih Cırıt <mfc@leodrive.ai>
(cherry picked from commit 9c098e544e)

Co-authored-by: M. Fatih Cırıt <xmfcx@users.noreply.github.com>
2023-12-01 17:04:30 -05:00
Yadunund
da3d2f49b3 21.0.4 2023-11-17 11:27:34 +08:00
Yadunund
a043349ecc Update changelogs
Signed-off-by: Yadunund <yadunund@openrobotics.org>
2023-11-17 11:27:20 +08:00
mergify[bot]
abcdcc4ed7 Disable the loaned messages inside the executor. (#2335) (#2365)
* Disable the loaned messages inside the executor.

They are currently unsafe to use; see the comment in the
commit for more information.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
(cherry picked from commit f294488e17)

Co-authored-by: Chris Lalancette <clalancette@gmail.com>
2023-11-09 14:01:26 -05:00
mergify[bot]
613bcc52ba Add missing 'enable_rosout' comments (#2345) (#2346)
Signed-off-by: Jiaqi Li <ljq0831@qq.com>
(cherry picked from commit fff009a751)

Co-authored-by: Jiaqi Li <ljq0831@qq.com>
2023-10-31 08:17:46 -07:00
mergify[bot]
82a8dba6c3 address rate related flaky tests. (#2329) (#2341)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
(cherry picked from commit fcbe64cff4)

Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-10-26 07:45:40 -07:00
Chris Lalancette
c67720e95c Add missing stdexcept include (#2186) (#2333)
Signed-off-by: Øystein Sture <os@skarvtech.com>
Co-authored-by: Øystein Sture <oysstu@users.noreply.github.com>
2023-10-10 15:26:10 -04:00
mergify[bot]
1ddf865efe Update SignalHandler get_global_signal_handler to avoid complex types in static memory (#2316) (#2322)
* Update SignalHandler get_global_signal_handler to avoid complex types in static memory

This was flagged by msan as a problem.

There's a description of why this is a potential problem here: https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables

Signed-off-by: Tully Foote <tullyfoote@intrinsic.ai>
Co-authored-by: William Woodall <william+github@osrfoundation.org>
(cherry picked from commit 7c1143dc15)
2023-10-04 14:56:06 -07:00
mergify[bot]
6af511f79f Add missing header required by the rclcpp::NodeOptions type (#2324) (#2325)
Signed-off-by: Ignacio Vizzo <ignacio@dexory.com>
(cherry picked from commit d6bd8baac5)

Co-authored-by: Ignacio Vizzo <ignaciovizzo@gmail.com>
2023-10-04 11:15:10 -04:00
mergify[bot]
fbb78ec975 Fix C++20 allocator construct deprecation (#2292) (#2318)
Signed-off-by: Guilherme Rodrigues <guilherme.rodrigues@ait.ac.at>
(cherry picked from commit fa732b9ee8)

Co-authored-by: AiVerisimilitude <133206333+AiVerisimilitude@users.noreply.github.com>
2023-09-27 20:39:53 -04:00
mergify[bot]
b82da1ade4 Topic correct typeadapter deduction (#2294) (#2298)
* fix TypeAdapter deduction

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
(cherry picked from commit 5e152d77d8)

Co-authored-by: Chen Lihui <lihui.chen@sony.com>
2023-09-14 17:19:04 -07:00
Yadunund
45df3555d2 21.0.3 2023-09-08 13:44:12 +08:00
Yadunund
3fa5bc49d6 Update changelogs
Signed-off-by: Yadunund <yadunund@openrobotics.org>
2023-09-08 13:43:56 +08:00
mergify[bot]
5dcd5a39a4 Do not crash Executor when send_response fails due to client failure. (#2276) (#2279)
* Do not crash Executor when send_response fails due to client failure.

Related to https://github.com/ros2/ros2/issues/1253

It is not sane that a faulty client can crash our service Executor, as
discussed in the referred issue, if the client is not setup properly,
send_response may return RCL_RET_TIMEOUT, we should not throw an error
in this case.

Signed-off-by: Zang MingJie <zealot0630@gmail.com>

* Update rclcpp/include/rclcpp/service.hpp

Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Signed-off-by: Zang MingJie <zealot0630@gmail.com>

* address review comments.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Zang MingJie <zealot0630@gmail.com>
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Zang MingJie <zealot0630@gmail.com>
(cherry picked from commit fbe8f28cd1)

Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-09-01 08:23:43 -07:00
mergify[bot]
7b7531bfd6 Switch lifecycle to use the RCLCPP macros. (backport #2233) (#2244)
* Switch lifecycle to use the RCLCPP macros. (#2233)

This ensures that they'll go out to /rosout and the disk.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
(cherry picked from commit 945d254e32)
2023-07-24 11:54:32 -04:00
Emerson Knapp
6d4a99f815 [Iron] Add new node interface TypeDescriptionsInterface to provide GetTypeDescription service (backport #2224) (#2236)
* Add new node interface TypeDescriptionsInterface to provide GetTypeDescription service (#2224)

* TypeDescriptions interface with readonly param configuration

* Add parameter descriptor, to make read only

* example of spinning in thread for get_type_description service

* Add a basic test for the new interface

* Fix tests with new parameter

* Add comments about builtin parameters

* Hide new member for ABI stability

* Add typedescription interface smoke test

Signed-off-by: Emerson Knapp <emerson.b.knapp@gmail.com>
Signed-off-by: William Woodall <william@osrfoundation.org>
2023-07-18 08:24:54 -04:00
Yadunund
052c075052 21.0.2 2023-07-14 01:21:56 +08:00
Yadunund
193c252036 Update Changelogs
Signed-off-by: Yadunund <yadunund@openrobotics.org>
2023-07-14 01:21:40 +08:00
mergify[bot]
efbb9b6c89 warning: comparison of integer expressions of different signedness (#2219) (#2222)
https://github.com/ros2/rclcpp/pull/2167#issuecomment-1597197552

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
(cherry picked from commit fe2e0e4c64)

Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-06-23 13:00:42 -04:00
mergify[bot]
3506dd1227 Fix race condition in events-executor (#2177) (#2191)
The initial implementation of the events-executor contained a bug where the executor
would end up in an inconsistent state and stop processing interrupt/shutdown notifications.
Manually adding a node to the executor results in a) producing a notify waitable event
and b) refreshing the executor collections.
The inconsistent state would happen if the event was processed before the collections were
finished to be refreshed: the executor would pick up the event but be unable to process it.
This would leave the `notify_waitable_event_pushed_` flag to true, preventing additional
notify waitable events to be pushed.
The behavior is observable only under heavy load.

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
(cherry picked from commit 6e1fea14e1)

Co-authored-by: Alberto Soragna <alberto.soragna@gmail.com>
2023-05-31 08:15:45 -05:00
Chris Lalancette
7a837496bd 21.0.1 2023-05-11 14:00:42 +00:00
Chris Lalancette
cd784f6612 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-05-11 14:00:36 +00:00
mergify[bot]
7aa390d5b1 Fix delivered message kind (#2175) (#2178)
Signed-off-by: methylDragon <methylDragon@gmail.com>
(cherry picked from commit 6ca1023ef7)

Co-authored-by: methylDragon <methylDragon@gmail.com>
2023-05-02 11:21:27 -04:00
65 changed files with 789 additions and 568 deletions

View File

@@ -2,31 +2,38 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
21.3.0 (2023-06-12)
21.0.5 (2024-02-07)
-------------------
* 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
* Fix data race in EventHandlerBase (`#2387 <https://github.com/ros2/rclcpp/issues/2387>`_)
* Contributors: mauropasse
21.2.0 (2023-06-07)
21.0.4 (2023-11-17)
-------------------
* remove nolint since ament_cpplint updated for the c++17 header (`#2198 <https://github.com/ros2/rclcpp/issues/2198>`_)
* Feature/available capacity of ipm (`#2173 <https://github.com/ros2/rclcpp/issues/2173>`_)
* add mutex to protect events_executor current entity collection (`#2187 <https://github.com/ros2/rclcpp/issues/2187>`_)
* Declare rclcpp callbacks before the rcl entities (`#2024 <https://github.com/ros2/rclcpp/issues/2024>`_)
* Contributors: Alberto Soragna, Chen Lihui, DensoADAS, mauropasse
* Disable the loaned messages inside the executor. (`#2365 <https://github.com/ros2/rclcpp/issues/2365>`_)
* Add missing 'enable_rosout' comments (`#2346 <https://github.com/ros2/rclcpp/issues/2346>`_)
* Address rate related flaky tests. (`#2341 <https://github.com/ros2/rclcpp/issues/2341>`_)
* Add missing stdexcept include (`#2333 <https://github.com/ros2/rclcpp/issues/2333>`_)
* Update SignalHandler get_global_signal_handler to avoid complex types in static memory (`#2322 <https://github.com/ros2/rclcpp/issues/2322>`_)
* Fix C++20 allocator construct deprecation (`#2318 <https://github.com/ros2/rclcpp/issues/2318>`_)
* Topic correct typeadapter deduction (`#2298 <https://github.com/ros2/rclcpp/issues/2298>`_)
* Contributors: AiVerisimilitude, Chen Lihui, Chris Lalancette, Jiaqi Li, Øystein Sture, Tomoya Fujita, William Woodall
21.1.1 (2023-05-11)
21.0.3 (2023-09-08)
-------------------
* Fix race condition in events-executor (`#2177 <https://github.com/ros2/rclcpp/issues/2177>`_)
* Add missing stdexcept include (`#2186 <https://github.com/ros2/rclcpp/issues/2186>`_)
* Fix a format-security warning when building with clang (`#2171 <https://github.com/ros2/rclcpp/issues/2171>`_)
* Fix delivered message kind (`#2175 <https://github.com/ros2/rclcpp/issues/2175>`_)
* Contributors: Alberto Soragna, Chris Lalancette, methylDragon, Øystein Sture
* Do not crash Executor when send_response fails due to client failure. (`#2279 <https://github.com/ros2/rclcpp/issues/2279>`_)
* Add new node interface TypeDescriptionsInterface to provide GetTypeDescription service (`#2236 <https://github.com/ros2/rclcpp/issues/2236>`_)
* Contributors: Emerson Knapp, Tomoya Fujita, Zang MingJie
21.1.0 (2023-04-27)
21.0.2 (2023-07-14)
-------------------
* Fix warnings related to comparison of integer expressions of different signedness (`#2222 <https://github.com/ros2/rclcpp/issues/2222>`_)
* Fix race condition in events-executor (`#2191 <https://github.com/ros2/rclcpp/issues/2191>`_)
* Contributors: Alberto Soragna, Tomoya Fujita
21.0.1 (2023-05-11)
-------------------
* Fix delivered message kind (`#2175 <https://github.com/ros2/rclcpp/issues/2175>`_) (`#2178 <https://github.com/ros2/rclcpp/issues/2178>`_)
* Contributors: mergify[bot]
21.0.0 (2023-04-18)
-------------------

View File

@@ -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

View File

@@ -156,7 +156,7 @@ public:
const std::shared_ptr<rmw_request_id_t> & request_header,
std::shared_ptr<typename ServiceT::Request> request)
{
TRACETOOLS_TRACEPOINT(callback_start, static_cast<const void *>(this), false);
TRACEPOINT(callback_start, static_cast<const void *>(this), false);
if (std::holds_alternative<std::monostate>(callback_)) {
// TODO(ivanpauno): Remove the set method, and force the users of this class
// to pass a callback at construnciton.
@@ -182,7 +182,7 @@ public:
const auto & cb = std::get<SharedPtrWithRequestHeaderCallback>(callback_);
cb(request_header, std::move(request), response);
}
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
TRACEPOINT(callback_end, static_cast<const void *>(this));
return response;
}
@@ -191,9 +191,9 @@ public:
#ifndef TRACETOOLS_DISABLED
std::visit(
[this](auto && arg) {
if (TRACETOOLS_TRACEPOINT_ENABLED(rclcpp_callback_register)) {
if (TRACEPOINT_ENABLED(rclcpp_callback_register)) {
char * symbol = tracetools::get_symbol(arg);
TRACETOOLS_DO_TRACEPOINT(
DO_TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
symbol);

View File

@@ -20,7 +20,7 @@
#include <stdexcept>
#include <type_traits>
#include <utility>
#include <variant>
#include <variant> // NOLINT[build/include_order]
#include "rosidl_runtime_cpp/traits.hpp"
#include "tracetools/tracetools.h"
@@ -492,7 +492,7 @@ public:
std::shared_ptr<ROSMessageType> message,
const rclcpp::MessageInfo & message_info)
{
TRACETOOLS_TRACEPOINT(callback_start, static_cast<const void *>(this), false);
TRACEPOINT(callback_start, static_cast<const void *>(this), false);
// Check if the variant is "unset", throw if it is.
if (callback_variant_.index() == 0) {
if (std::get<0>(callback_variant_) == nullptr) {
@@ -583,7 +583,7 @@ public:
static_assert(always_false_v<T>, "unhandled callback type");
}
}, callback_variant_);
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
TRACEPOINT(callback_end, static_cast<const void *>(this));
}
// Dispatch when input is a serialized message and the output could be anything.
@@ -592,7 +592,7 @@ public:
std::shared_ptr<rclcpp::SerializedMessage> serialized_message,
const rclcpp::MessageInfo & message_info)
{
TRACETOOLS_TRACEPOINT(callback_start, static_cast<const void *>(this), false);
TRACEPOINT(callback_start, static_cast<const void *>(this), false);
// Check if the variant is "unset", throw if it is.
if (callback_variant_.index() == 0) {
if (std::get<0>(callback_variant_) == nullptr) {
@@ -663,7 +663,7 @@ public:
static_assert(always_false_v<T>, "unhandled callback type");
}
}, callback_variant_);
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
TRACEPOINT(callback_end, static_cast<const void *>(this));
}
void
@@ -671,7 +671,7 @@ public:
std::shared_ptr<const SubscribedType> message,
const rclcpp::MessageInfo & message_info)
{
TRACETOOLS_TRACEPOINT(callback_start, static_cast<const void *>(this), true);
TRACEPOINT(callback_start, static_cast<const void *>(this), true);
// Check if the variant is "unset", throw if it is.
if (callback_variant_.index() == 0) {
if (std::get<0>(callback_variant_) == nullptr) {
@@ -793,7 +793,7 @@ public:
static_assert(always_false_v<T>, "unhandled callback type");
}
}, callback_variant_);
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
TRACEPOINT(callback_end, static_cast<const void *>(this));
}
void
@@ -801,7 +801,7 @@ public:
std::unique_ptr<SubscribedType, SubscribedTypeDeleter> message,
const rclcpp::MessageInfo & message_info)
{
TRACETOOLS_TRACEPOINT(callback_start, static_cast<const void *>(this), true);
TRACEPOINT(callback_start, static_cast<const void *>(this), true);
// Check if the variant is "unset", throw if it is.
if (callback_variant_.index() == 0) {
if (std::get<0>(callback_variant_) == nullptr) {
@@ -927,7 +927,7 @@ public:
static_assert(always_false_v<T>, "unhandled callback type");
}
}, callback_variant_);
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
TRACEPOINT(callback_end, static_cast<const void *>(this));
}
constexpr
@@ -965,9 +965,9 @@ public:
#ifndef TRACETOOLS_DISABLED
std::visit(
[this](auto && callback) {
if (TRACETOOLS_TRACEPOINT_ENABLED(rclcpp_callback_register)) {
if (TRACEPOINT_ENABLED(rclcpp_callback_register)) {
char * symbol = tracetools::get_symbol(callback);
TRACETOOLS_DO_TRACEPOINT(
DO_TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
symbol);

View File

@@ -20,13 +20,13 @@
#include <future>
#include <memory>
#include <mutex>
#include <optional>
#include <optional> // NOLINT, cpplint doesn't think this is a cpp std header
#include <sstream>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <variant>
#include <variant> // NOLINT
#include <vector>
#include "rcl/client.h"
@@ -363,16 +363,12 @@ protected:
std::shared_ptr<rclcpp::Context> context_;
rclcpp::Logger node_logger_;
std::recursive_mutex callback_mutex_;
// It is important to declare on_new_response_callback_ before
// client_handle_, so on destruction the client is
// destroyed first. Otherwise, the rmw client callback
// would point briefly to a destroyed function.
std::function<void(size_t)> on_new_response_callback_{nullptr};
// Declare client_handle_ after callback
std::shared_ptr<rcl_client_t> client_handle_;
std::atomic<bool> in_use_by_wait_set_{false};
std::recursive_mutex callback_mutex_;
std::function<void(size_t)> on_new_response_callback_{nullptr};
};
template<typename ServiceT>

View File

@@ -260,6 +260,16 @@ public:
}
}
~EventHandler()
{
// Since the rmw event listener holds a reference to the
// "on ready" callback, we need to clear it on destruction of this class.
// This clearing is not needed for other rclcpp entities like pub/subs, since
// they do own the underlying rmw entities, which are destroyed
// on their rclcpp destructors, thus no risk of dangling pointers.
clear_on_ready_callback();
}
/// Take data so that the callback cannot be scheduled again
std::shared_ptr<void>
take_data() override

View File

@@ -33,7 +33,6 @@ public:
virtual void clear() = 0;
virtual bool has_data() const = 0;
virtual size_t available_capacity() const = 0;
};
} // namespace buffers

View File

@@ -44,7 +44,6 @@ public:
virtual bool has_data() const = 0;
virtual bool use_take_shared_method() const = 0;
virtual size_t available_capacity() const = 0;
};
template<
@@ -96,7 +95,7 @@ public:
buffer_ = std::move(buffer_impl);
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_buffer_to_ipb,
static_cast<const void *>(buffer_.get()),
static_cast<const void *>(this));
@@ -144,11 +143,6 @@ public:
return std::is_same<BufferT, MessageSharedPtr>::value;
}
size_t available_capacity() const override
{
return buffer_->available_capacity();
}
private:
std::unique_ptr<BufferImplementationBase<BufferT>> buffer_;

View File

@@ -52,10 +52,7 @@ public:
if (capacity == 0) {
throw std::invalid_argument("capacity must be a positive, non-zero value");
}
TRACETOOLS_TRACEPOINT(
rclcpp_construct_ring_buffer,
static_cast<const void *>(this),
capacity_);
TRACEPOINT(rclcpp_construct_ring_buffer, static_cast<const void *>(this), capacity_);
}
virtual ~RingBufferImplementation() {}
@@ -72,7 +69,7 @@ public:
write_index_ = next_(write_index_);
ring_buffer_[write_index_] = std::move(request);
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_ring_buffer_enqueue,
static_cast<const void *>(this),
write_index_,
@@ -101,7 +98,7 @@ public:
}
auto request = std::move(ring_buffer_[read_index_]);
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_ring_buffer_dequeue,
static_cast<const void *>(this),
read_index_,
@@ -151,21 +148,9 @@ public:
return is_full_();
}
/// Get the remaining capacity to store messages
/**
* This member function is thread-safe.
*
* \return the number of free capacity for new messages
*/
size_t available_capacity() const
{
std::lock_guard<std::mutex> lock(mutex_);
return available_capacity_();
}
void clear()
{
TRACETOOLS_TRACEPOINT(rclcpp_ring_buffer_clear, static_cast<const void *>(this));
TRACEPOINT(rclcpp_ring_buffer_clear, static_cast<const void *>(this));
}
private:
@@ -204,17 +189,6 @@ private:
return size_ == capacity_;
}
/// Get the remaining capacity to store messages
/**
* This member function is not thread-safe.
*
* \return the number of free capacity for new messages
*/
inline size_t available_capacity_() const
{
return capacity_ - size_;
}
size_t capacity_;
std::vector<BufferT> ring_buffer_;

View File

@@ -274,11 +274,8 @@ private:
rclcpp::experimental::executors::EventsQueue::UniquePtr events_queue_;
std::shared_ptr<rclcpp::executors::ExecutorEntitiesCollector> entities_collector_;
std::shared_ptr<rclcpp::executors::ExecutorNotifyWaitable> notify_waitable_;
/// Mutex to protect the current_entities_collection_
std::recursive_mutex collection_mutex_;
std::shared_ptr<rclcpp::executors::ExecutorEntitiesCollection> current_entities_collection_;
std::shared_ptr<rclcpp::executors::ExecutorNotifyWaitable> notify_waitable_;
/// Flag used to reduce the number of unnecessary waitable events
std::atomic<bool> notify_waitable_event_pushed_ {false};

View File

@@ -306,11 +306,6 @@ public:
rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr
get_subscription_intra_process(uint64_t intra_process_subscription_id);
/// Return the lowest available capacity for all subscription buffers for a publisher id.
RCLCPP_PUBLIC
size_t
lowest_available_capacity(const uint64_t intra_process_publisher_id) const;
private:
struct SplittedSubscriptions
{
@@ -486,13 +481,13 @@ private:
"subscription use different allocator types, which is not supported");
}
if constexpr (rclcpp::TypeAdapter<MessageT>::is_specialized::value) {
if constexpr (rclcpp::TypeAdapter<MessageT, ROSMessageType>::is_specialized::value) {
ROSMessageTypeAllocator ros_message_alloc(allocator);
auto ptr = ros_message_alloc.allocate(1);
ros_message_alloc.construct(ptr);
auto ptr = ROSMessageTypeAllocatorTraits::allocate(ros_message_alloc, 1);
ROSMessageTypeAllocatorTraits::construct(ros_message_alloc, ptr);
ROSMessageTypeDeleter deleter;
allocator::set_allocator_for_deleter(&deleter, &allocator);
rclcpp::TypeAdapter<MessageT>::convert_to_ros_message(*message, *ptr);
rclcpp::TypeAdapter<MessageT, ROSMessageType>::convert_to_ros_message(*message, *ptr);
auto ros_msg = std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, deleter);
ros_message_subscription->provide_intra_process_message(std::move(ros_msg));
} else {

View File

@@ -87,7 +87,7 @@ public:
buffer_type),
any_callback_(callback)
{
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_subscription_callback_added,
static_cast<const void *>(this),
static_cast<const void *>(&any_callback_));

View File

@@ -62,11 +62,6 @@ public:
void
add_to_wait_set(rcl_wait_set_t * wait_set) override;
RCLCPP_PUBLIC
virtual
size_t
available_capacity() const = 0;
bool
is_ready(rcl_wait_set_t * wait_set) override = 0;

View File

@@ -93,7 +93,7 @@ public:
buffer_type,
qos_profile,
std::make_shared<Alloc>(subscribed_type_allocator_));
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_ipb_to_subscription,
static_cast<const void *>(buffer_.get()),
static_cast<const void *>(this));
@@ -169,11 +169,6 @@ public:
return buffer_->use_take_shared_method();
}
size_t available_capacity() const override
{
return buffer_->available_capacity();
}
protected:
void
trigger_guard_condition() override

View File

@@ -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"
@@ -1454,6 +1455,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
@@ -1591,6 +1597,11 @@ private:
const rclcpp::NodeOptions node_options_;
const std::string sub_namespace_;
const std::string effective_namespace_;
/// Static map(s) containing extra member variables for Node without changing its ABI.
// See node.cpp for more details.
class BackportMembers;
static BackportMembers backport_members_;
};
} // namespace rclcpp

View File

@@ -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

View File

@@ -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_

View File

@@ -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_

View File

@@ -43,6 +43,7 @@ public:
* - arguments = {}
* - parameter_overrides = {}
* - use_global_arguments = true
* - enable_rosout = true
* - use_intra_process_comms = false
* - enable_topic_statistics = false
* - start_parameter_services = true

View File

@@ -48,7 +48,7 @@ public:
*
* Example Usage:
*
* If you have received a parameter event and are only interested in parameters foo and
* If you have recieved a parameter event and are only interested in parameters foo and
* bar being added or changed but don't care about deletion.
*
* ```cpp

View File

@@ -421,7 +421,7 @@ protected:
void
do_inter_process_publish(const ROSMessageType & msg)
{
TRACETOOLS_TRACEPOINT(rclcpp_publish, nullptr, static_cast<const void *>(&msg));
TRACEPOINT(rclcpp_publish, nullptr, static_cast<const void *>(&msg));
auto status = rcl_publish(publisher_handle_.get(), &msg, nullptr);
if (RCL_RET_PUBLISHER_INVALID == status) {
@@ -484,7 +484,7 @@ protected:
if (!msg) {
throw std::runtime_error("cannot publish msg which is a null pointer");
}
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_intra_publish,
static_cast<const void *>(publisher_handle_.get()),
msg.get());
@@ -506,7 +506,7 @@ protected:
if (!msg) {
throw std::runtime_error("cannot publish msg which is a null pointer");
}
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_intra_publish,
static_cast<const void *>(publisher_handle_.get()),
msg.get());
@@ -529,7 +529,7 @@ protected:
if (!msg) {
throw std::runtime_error("cannot publish msg which is a null pointer");
}
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_intra_publish,
static_cast<const void *>(publisher_handle_.get()),
msg.get());

View File

@@ -215,17 +215,6 @@ public:
std::vector<rclcpp::NetworkFlowEndpoint>
get_network_flow_endpoints() const;
/// Return the lowest available capacity for all subscription buffers.
/**
* For intraprocess communication return the lowest buffer capacity for all subscriptions.
* If intraprocess is disabled or no intraprocess subscriptions present, return maximum of size_t.
* On failure return 0.
* \return lowest buffer capacity for all subscriptions
*/
RCLCPP_PUBLIC
size_t
lowest_available_ipm_capacity() const;
/// Wait until all published messages are acknowledged or until the specified timeout elapses.
/**
* This method waits until all published messages are acknowledged by all matching

View File

@@ -265,19 +265,15 @@ protected:
std::shared_ptr<rcl_node_t> node_handle_;
std::recursive_mutex callback_mutex_;
// It is important to declare on_new_request_callback_ before
// service_handle_, so on destruction the service is
// destroyed first. Otherwise, the rmw service callback
// would point briefly to a destroyed function.
std::function<void(size_t)> on_new_request_callback_{nullptr};
// Declare service_handle_ after callback
std::shared_ptr<rcl_service_t> service_handle_;
bool owns_rcl_handle_ = true;
rclcpp::Logger node_logger_;
std::atomic<bool> in_use_by_wait_set_{false};
std::recursive_mutex callback_mutex_;
std::function<void(size_t)> on_new_request_callback_{nullptr};
};
template<typename ServiceT>
@@ -352,7 +348,7 @@ public:
rclcpp::exceptions::throw_from_rcl_error(ret, "could not create service");
}
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_service_callback_added,
static_cast<const void *>(get_service_handle().get()),
static_cast<const void *>(&any_callback_));
@@ -387,7 +383,7 @@ public:
}
service_handle_ = service_handle;
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_service_callback_added,
static_cast<const void *>(get_service_handle().get()),
static_cast<const void *>(&any_callback_));
@@ -424,7 +420,7 @@ public:
// In this case, rcl owns the service handle memory
service_handle_ = std::shared_ptr<rcl_service_t>(new rcl_service_t);
service_handle_->impl = service_handle->impl;
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_service_callback_added,
static_cast<const void *>(get_service_handle().get()),
static_cast<const void *>(&any_callback_));
@@ -486,6 +482,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");
}

View File

@@ -185,7 +185,7 @@ public:
this->get_topic_name(), // important to get like this, as it has the fully-qualified name
qos_profile,
resolve_intra_process_buffer_type(options_.intra_process_buffer_type, callback));
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_subscription_init,
static_cast<const void *>(get_subscription_handle().get()),
static_cast<const void *>(subscription_intra_process_.get()));
@@ -201,11 +201,11 @@ public:
this->subscription_topic_statistics_ = std::move(subscription_topic_statistics);
}
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_subscription_init,
static_cast<const void *>(get_subscription_handle().get()),
static_cast<const void *>(this));
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_subscription_callback_added,
static_cast<const void *>(this),
static_cast<const void *>(&any_callback_));

View File

@@ -645,14 +645,6 @@ protected:
rclcpp::node_interfaces::NodeBaseInterface * const node_base_;
std::shared_ptr<rcl_node_t> node_handle_;
std::recursive_mutex callback_mutex_;
// It is important to declare on_new_message_callback_ before
// subscription_handle_, so on destruction the subscription is
// destroyed first. Otherwise, the rmw subscription callback
// would point briefly to a destroyed function.
std::function<void(size_t)> on_new_message_callback_{nullptr};
// Declare subscription_handle_ after callback
std::shared_ptr<rcl_subscription_t> subscription_handle_;
std::shared_ptr<rcl_subscription_t> intra_process_subscription_handle_;
rclcpp::Logger node_logger_;
@@ -677,6 +669,9 @@ private:
std::atomic<bool> intra_process_subscription_waitable_in_use_by_wait_set_{false};
std::unordered_map<rclcpp::EventHandlerBase *,
std::atomic<bool>> qos_events_in_use_by_wait_set_;
std::recursive_mutex callback_mutex_;
std::function<void(size_t)> on_new_message_callback_{nullptr};
};
} // namespace rclcpp

View File

@@ -223,14 +223,14 @@ public:
)
: TimerBase(clock, period, context), callback_(std::forward<FunctorT>(callback))
{
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_timer_callback_added,
static_cast<const void *>(get_timer_handle().get()),
reinterpret_cast<const void *>(&callback_));
#ifndef TRACETOOLS_DISABLED
if (TRACETOOLS_TRACEPOINT_ENABLED(rclcpp_callback_register)) {
if (TRACEPOINT_ENABLED(rclcpp_callback_register)) {
char * symbol = tracetools::get_symbol(callback_);
TRACETOOLS_DO_TRACEPOINT(
DO_TRACEPOINT(
rclcpp_callback_register,
reinterpret_cast<const void *>(&callback_),
symbol);
@@ -269,9 +269,9 @@ public:
void
execute_callback() override
{
TRACETOOLS_TRACEPOINT(callback_start, reinterpret_cast<const void *>(&callback_), false);
TRACEPOINT(callback_start, reinterpret_cast<const void *>(&callback_), false);
execute_callback_delegate<>();
TRACETOOLS_TRACEPOINT(callback_end, reinterpret_cast<const void *>(&callback_));
TRACEPOINT(callback_end, reinterpret_cast<const void *>(&callback_));
}
// void specialization

View File

@@ -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.3.0</version>
<version>21.0.5</version>
<description>The ROS client library in C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -496,7 +496,7 @@ Context::sleep_for(const std::chrono::nanoseconds & nanoseconds)
std::unique_lock<std::mutex> lock(interrupt_mutex_);
auto start = std::chrono::steady_clock::now();
// this will release the lock while waiting
interrupt_condition_variable_.wait_for(lock, nanoseconds);
interrupt_condition_variable_.wait_for(lock, time_left);
time_left -= std::chrono::steady_clock::now() - start;
}
} while (time_left > std::chrono::nanoseconds::zero() && this->is_valid());

View File

@@ -39,13 +39,6 @@ UnsupportedEventTypeException::UnsupportedEventTypeException(
EventHandlerBase::~EventHandlerBase()
{
// Since the rmw event listener holds a reference to
// this callback, we need to clear it on destruction of this class.
// This clearing is not needed for other rclcpp entities like pub/subs, since
// they do own the underlying rmw entities, which are destroyed
// on their rclcpp destructors, thus no risk of dangling pointers.
clear_on_ready_callback();
if (rcl_event_fini(&event_handle_) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",

View File

@@ -525,13 +525,13 @@ Executor::execute_any_executable(AnyExecutable & any_exec)
return;
}
if (any_exec.timer) {
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_executor_execute,
static_cast<const void *>(any_exec.timer->get_timer_handle().get()));
execute_timer(any_exec.timer);
}
if (any_exec.subscription) {
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_executor_execute,
static_cast<const void *>(any_exec.subscription->get_subscription_handle().get()));
execute_subscription(any_exec.subscription);
@@ -653,6 +653,11 @@ Executor::execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
subscription->get_topic_name(),
[&]() {return subscription->take_type_erased(message.get(), message_info);},
[&]() {subscription->handle_message(message, message_info);});
// TODO(clalancette): In the case that the user is using the MessageMemoryPool,
// and they take a shared_ptr reference to the message in the callback, this can
// inadvertently return the message to the pool when the user is still using it.
// This is a bug that needs to be fixed in the pool, and we should probably have
// a custom deleter for the message that actually does the return_message().
subscription->return_message(message);
}
break;
@@ -726,7 +731,7 @@ Executor::execute_client(
void
Executor::wait_for_work(std::chrono::nanoseconds timeout)
{
TRACETOOLS_TRACEPOINT(rclcpp_executor_wait_for_work, timeout.count());
TRACEPOINT(rclcpp_executor_wait_for_work, timeout.count());
{
std::lock_guard<std::mutex> guard(mutex_);
@@ -882,7 +887,7 @@ Executor::get_next_ready_executable_from_map(
const rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap &
weak_groups_to_nodes)
{
TRACETOOLS_TRACEPOINT(rclcpp_executor_get_next_ready);
TRACEPOINT(rclcpp_executor_get_next_ready);
bool success = false;
std::lock_guard<std::mutex> guard{mutex_};
// Check the timers to see if there are any that are ready

View File

@@ -273,13 +273,10 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
switch (event.type) {
case ExecutorEventType::CLIENT_EVENT:
{
rclcpp::ClientBase::SharedPtr client;
{
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
client = this->retrieve_entity(
static_cast<const rcl_client_t *>(event.entity_key),
current_entities_collection_->clients);
}
auto client = this->retrieve_entity(
static_cast<const rcl_client_t *>(event.entity_key),
current_entities_collection_->clients);
if (client) {
for (size_t i = 0; i < event.num_events; i++) {
execute_client(client);
@@ -290,13 +287,9 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
}
case ExecutorEventType::SUBSCRIPTION_EVENT:
{
rclcpp::SubscriptionBase::SharedPtr subscription;
{
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
subscription = this->retrieve_entity(
static_cast<const rcl_subscription_t *>(event.entity_key),
current_entities_collection_->subscriptions);
}
auto subscription = this->retrieve_entity(
static_cast<const rcl_subscription_t *>(event.entity_key),
current_entities_collection_->subscriptions);
if (subscription) {
for (size_t i = 0; i < event.num_events; i++) {
execute_subscription(subscription);
@@ -306,13 +299,10 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
}
case ExecutorEventType::SERVICE_EVENT:
{
rclcpp::ServiceBase::SharedPtr service;
{
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
service = this->retrieve_entity(
static_cast<const rcl_service_t *>(event.entity_key),
current_entities_collection_->services);
}
auto service = this->retrieve_entity(
static_cast<const rcl_service_t *>(event.entity_key),
current_entities_collection_->services);
if (service) {
for (size_t i = 0; i < event.num_events; i++) {
execute_service(service);
@@ -329,13 +319,9 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
}
case ExecutorEventType::WAITABLE_EVENT:
{
rclcpp::Waitable::SharedPtr waitable;
{
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
waitable = this->retrieve_entity(
static_cast<const rclcpp::Waitable *>(event.entity_key),
current_entities_collection_->waitables);
}
auto waitable = this->retrieve_entity(
static_cast<const rclcpp::Waitable *>(event.entity_key),
current_entities_collection_->waitables);
if (waitable) {
for (size_t i = 0; i < event.num_events; i++) {
auto data = waitable->take_data_by_entity_id(event.waitable_data);
@@ -400,7 +386,6 @@ EventsExecutor::get_automatically_added_callback_groups_from_nodes()
void
EventsExecutor::refresh_current_collection_from_callback_groups()
{
// Build the new collection
this->entities_collector_->update_collections();
auto callback_groups = this->entities_collector_->get_all_callback_groups();
rclcpp::executors::ExecutorEntitiesCollection new_collection;
@@ -415,9 +400,6 @@ EventsExecutor::refresh_current_collection_from_callback_groups()
// To do it, we need to add the notify waitable as an entry in both the new and
// current collections such that it's neither added or removed.
this->add_notify_waitable_to_collection(new_collection.waitables);
// Acquire lock before modifying the current collection
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
this->add_notify_waitable_to_collection(current_entities_collection_->waitables);
this->refresh_current_collection(new_collection);
@@ -427,9 +409,6 @@ void
EventsExecutor::refresh_current_collection(
const rclcpp::executors::ExecutorEntitiesCollection & new_collection)
{
// Acquire lock before modifying the current collection
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
current_entities_collection_->timers.update(
new_collection.timers,
[this](rclcpp::TimerBase::SharedPtr timer) {timers_manager_->add_timer(timer);},

View File

@@ -225,52 +225,5 @@ IntraProcessManager::can_communicate(
return true;
}
size_t
IntraProcessManager::lowest_available_capacity(const uint64_t intra_process_publisher_id) const
{
size_t capacity = std::numeric_limits<size_t>::max();
auto publisher_it = pub_to_subs_.find(intra_process_publisher_id);
if (publisher_it == pub_to_subs_.end()) {
// Publisher is either invalid or no longer exists.
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Calling lowest_available_capacity for invalid or no longer existing publisher id");
return 0u;
}
if (publisher_it->second.take_shared_subscriptions.empty() &&
publisher_it->second.take_ownership_subscriptions.empty())
{
// no subscriptions available
return 0u;
}
auto available_capacity = [this, &capacity](const uint64_t intra_process_subscription_id)
{
auto subscription_it = subscriptions_.find(intra_process_subscription_id);
if (subscription_it != subscriptions_.end()) {
auto subscription = subscription_it->second.lock();
if (subscription) {
capacity = std::min(capacity, subscription->available_capacity());
}
} else {
// Subscription is either invalid or no longer exists.
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Calling available_capacity for invalid or no longer existing subscription id");
}
};
for (const auto sub_id : publisher_it->second.take_shared_subscriptions) {
available_capacity(sub_id);
}
for (const auto sub_id : publisher_it->second.take_ownership_subscriptions) {
available_capacity(sub_id);
}
return capacity;
}
} // namespace experimental
} // namespace rclcpp

View File

@@ -17,7 +17,10 @@
#include <limits>
#include <map>
#include <memory>
#include <mutex>
#include <shared_mutex>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
@@ -36,6 +39,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 +113,72 @@ create_effective_namespace(const std::string & node_namespace, const std::string
} // namespace
/// \brief Associate new extra member variables with instances of Node without changing ABI.
/**
* It is used only for bugfixes or backported features that require new members.
* Atomically constructs/destroys all extra members.
* Node instance will register and remove itself, and use its methods to retrieve members.
* Note for performance consideration that accessing these members uses a map lookup.
*/
class Node::BackportMembers
{
public:
BackportMembers() = default;
~BackportMembers() = default;
/// \brief Add all backported members for a new Node.
/**
* \param[in] key Raw pointer to the Node instance that will use new members.
*/
void add(Node * key)
{
// Adding a new instance to the maps requires exclusive access
std::unique_lock lock(map_access_mutex_);
type_descriptions_map_.emplace(
key,
std::make_shared<rclcpp::node_interfaces::NodeTypeDescriptions>(
key->get_node_base_interface(),
key->get_node_logging_interface(),
key->get_node_parameters_interface(),
key->get_node_services_interface()));
}
/// \brief Remove the members for an instance of Node
/**
* \param[in] key Raw pointer to the Node
*/
void remove(const Node * key)
{
// Removing an instance from the maps requires exclusive access
std::unique_lock lock(map_access_mutex_);
type_descriptions_map_.erase(key);
}
/// \brief Retrieve the NodeTypeDescriptionsInterface for a Node.
/**
* \param[in] key Raw pointer to an instance of Node.
* \return A shared ptr to this Node's NodeTypeDescriptionsInterface instance.
*/
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr
get_node_type_descriptions_interface(const Node * key) const
{
// Multiple threads can retrieve from the maps at the same time
std::shared_lock lock(map_access_mutex_);
return type_descriptions_map_.at(key);
}
private:
/// \brief Map that stored TypeDescriptionsInterface members
std::unordered_map<
const Node *, rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr
> type_descriptions_map_;
/// \brief Controls access to all private maps
mutable std::shared_mutex map_access_mutex_;
};
// Definition of static member declaration
Node::BackportMembers Node::backport_members_;
Node::Node(
const std::string & node_name,
const NodeOptions & options)
@@ -211,6 +281,8 @@ Node::Node(
sub_namespace_(""),
effective_namespace_(create_effective_namespace(this->get_namespace(), sub_namespace_))
{
backport_members_.add(this);
// we have got what we wanted directly from the overrides,
// but declare the parameters anyway so they are visible.
rclcpp::detail::declare_qos_parameters(
@@ -272,6 +344,7 @@ Node::Node(
Node::~Node()
{
// release sub-interfaces in an order that allows them to consult with node_base during tear-down
backport_members_.remove(this);
node_waitables_.reset();
node_time_source_.reset();
node_parameters_.reset();
@@ -591,6 +664,12 @@ Node::get_node_topics_interface()
return node_topics_;
}
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr
Node::get_node_type_descriptions_interface()
{
return backport_members_.get_node_type_descriptions_interface(this);
}
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr
Node::get_node_services_interface()
{

View File

@@ -50,7 +50,7 @@ NodeTimers::add_timer(
std::string("failed to notify wait set on timer creation: ") + ex.what());
}
TRACETOOLS_TRACEPOINT(
TRACEPOINT(
rclcpp_timer_link_node,
static_cast<const void *>(timer->get_timer_handle().get()),
static_cast<const void *>(node_base_->get_rcl_node_handle()));

View 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

View File

@@ -384,22 +384,3 @@ std::vector<rclcpp::NetworkFlowEndpoint> PublisherBase::get_network_flow_endpoin
return network_flow_endpoint_vector;
}
size_t PublisherBase::lowest_available_ipm_capacity() const
{
if (!intra_process_is_enabled_) {
return 0u;
}
auto ipm = weak_ipm_.lock();
if (!ipm) {
// TODO(ivanpauno): should this raise an error?
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Intra process manager died for a publisher.");
return 0u;
}
return ipm->lowest_available_capacity(intra_process_publisher_id_);
}

View File

@@ -113,7 +113,7 @@ SignalHandler::get_logger()
SignalHandler &
SignalHandler::get_global_signal_handler()
{
static SignalHandler signal_handler;
static SignalHandler & signal_handler = *new SignalHandler();
return signal_handler;
}

View File

@@ -218,7 +218,7 @@ SubscriptionBase::take_type_erased(void * message_out, rclcpp::MessageInfo & mes
&message_info_out.get_rmw_message_info(),
nullptr // rmw_subscription_allocation_t is unused here
);
TRACETOOLS_TRACEPOINT(rclcpp_take, static_cast<const void *>(message_out));
TRACEPOINT(rclcpp_take, static_cast<const void *>(message_out));
if (RCL_RET_SUBSCRIPTION_TAKE_FAILED == ret) {
return false;
} else if (RCL_RET_OK != ret) {
@@ -298,7 +298,20 @@ SubscriptionBase::setup_intra_process(
bool
SubscriptionBase::can_loan_messages() const
{
return rcl_subscription_can_loan_messages(subscription_handle_.get());
bool retval = rcl_subscription_can_loan_messages(subscription_handle_.get());
if (retval) {
// TODO(clalancette): The loaned message interface is currently not safe to use with
// shared_ptr callbacks. If a user takes a copy of the shared_ptr, it can get freed from
// underneath them via rcl_return_loaned_message_from_subscription(). The correct solution is
// to return the loaned message in a custom deleter, but that needs to be carefully handled
// with locking. Warn the user about this until we fix it.
RCLCPP_WARN_ONCE(
this->node_logger_,
"Loaned messages are only safe with const ref subscription callbacks. "
"If you are using any other kind of subscriptions, "
"set the ROS_DISABLE_LOANED_MESSAGES environment variable to 1 (the default).");
}
return retval;
}
rclcpp::Waitable::SharedPtr

View File

@@ -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)

View File

@@ -858,7 +858,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 +867,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 +889,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 +905,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 +919,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());

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -238,75 +238,3 @@ TEST(TestIntraProcessBuffer, unique_buffer_consume) {
EXPECT_EQ(original_value, *popped_unique_msg);
EXPECT_EQ(original_message_pointer, popped_message_pointer);
}
/*
Check the available buffer capacity while storing and consuming data from an intra-process
buffer.
The initial available buffer capacity should equal the buffer size.
Inserting a message should decrease the available buffer capacity by 1.
Consuming a message should increase the available buffer capacity by 1.
*/
TEST(TestIntraProcessBuffer, available_capacity) {
using MessageT = char;
using Alloc = std::allocator<void>;
using Deleter = std::default_delete<MessageT>;
using SharedMessageT = std::shared_ptr<const MessageT>;
using UniqueMessageT = std::unique_ptr<MessageT, Deleter>;
using UniqueIntraProcessBufferT = rclcpp::experimental::buffers::TypedIntraProcessBuffer<
MessageT, Alloc, Deleter, UniqueMessageT>;
constexpr auto history_depth = 5u;
auto buffer_impl =
std::make_unique<rclcpp::experimental::buffers::RingBufferImplementation<UniqueMessageT>>(
history_depth);
UniqueIntraProcessBufferT intra_process_buffer(std::move(buffer_impl));
EXPECT_EQ(history_depth, intra_process_buffer.available_capacity());
auto original_unique_msg = std::make_unique<char>('a');
auto original_message_pointer = reinterpret_cast<std::uintptr_t>(original_unique_msg.get());
auto original_value = *original_unique_msg;
intra_process_buffer.add_unique(std::move(original_unique_msg));
EXPECT_EQ(history_depth - 1u, intra_process_buffer.available_capacity());
SharedMessageT popped_shared_msg;
popped_shared_msg = intra_process_buffer.consume_shared();
auto popped_message_pointer = reinterpret_cast<std::uintptr_t>(popped_shared_msg.get());
EXPECT_EQ(history_depth, intra_process_buffer.available_capacity());
EXPECT_EQ(original_value, *popped_shared_msg);
EXPECT_EQ(original_message_pointer, popped_message_pointer);
original_unique_msg = std::make_unique<char>('b');
original_message_pointer = reinterpret_cast<std::uintptr_t>(original_unique_msg.get());
original_value = *original_unique_msg;
intra_process_buffer.add_unique(std::move(original_unique_msg));
auto second_unique_msg = std::make_unique<char>('c');
auto second_message_pointer = reinterpret_cast<std::uintptr_t>(second_unique_msg.get());
auto second_value = *second_unique_msg;
intra_process_buffer.add_unique(std::move(second_unique_msg));
EXPECT_EQ(history_depth - 2u, intra_process_buffer.available_capacity());
UniqueMessageT popped_unique_msg;
popped_unique_msg = intra_process_buffer.consume_unique();
popped_message_pointer = reinterpret_cast<std::uintptr_t>(popped_unique_msg.get());
EXPECT_EQ(history_depth - 1u, intra_process_buffer.available_capacity());
EXPECT_EQ(original_value, *popped_unique_msg);
EXPECT_EQ(original_message_pointer, popped_message_pointer);
popped_unique_msg = intra_process_buffer.consume_unique();
popped_message_pointer = reinterpret_cast<std::uintptr_t>(popped_unique_msg.get());
EXPECT_EQ(history_depth, intra_process_buffer.available_capacity());
EXPECT_EQ(second_value, *popped_unique_msg);
EXPECT_EQ(second_message_pointer, popped_message_pointer);
}

View File

@@ -156,26 +156,18 @@ public:
{
message_ptr = reinterpret_cast<std::uintptr_t>(msg.get());
shared_msg = msg;
++num_msgs;
}
void add(MessageUniquePtr msg)
{
message_ptr = reinterpret_cast<std::uintptr_t>(msg.get());
unique_msg = std::move(msg);
++num_msgs;
}
void pop(std::uintptr_t & msg_ptr)
{
msg_ptr = message_ptr;
message_ptr = 0;
--num_msgs;
}
size_t size() const
{
return num_msgs;
}
// need to store the messages somewhere otherwise the memory address will be reused
@@ -183,8 +175,6 @@ public:
MessageUniquePtr unique_msg;
std::uintptr_t message_ptr;
// count add and pop
size_t num_msgs = 0u;
};
} // namespace mock
@@ -231,10 +221,6 @@ public:
return topic_name.c_str();
}
virtual
size_t
available_capacity() const = 0;
rclcpp::QoS qos_profile;
std::string topic_name;
};
@@ -294,12 +280,6 @@ public:
return take_shared_method;
}
size_t
available_capacity() const override
{
return qos_profile.depth() - buffer->size();
}
bool take_shared_method;
typename rclcpp::experimental::buffers::mock::IntraProcessBuffer<MessageT>::UniquePtr buffer;
@@ -732,91 +712,3 @@ TEST(TestIntraProcessManager, multiple_subscriptions_different_type) {
EXPECT_EQ(original_message_pointer, received_message_pointer_10);
EXPECT_NE(original_message_pointer, received_message_pointer_11);
}
/*
This tests the method "lowest_available_capacity":
- Creates 1 publisher.
- The available buffer capacity should be at least history size.
- Add 2 subscribers.
- Add everything to the intra-process manager.
- All the entities are expected to have different ids.
- Check the subscriptions count for the publisher.
- The available buffer capacity should be the history size.
- Publish one message (without receiving it).
- The available buffer capacity should decrease by 1.
- Publish another message (without receiving it).
- The available buffer capacity should decrease by 1.
- One subscriber receives one message.
- The available buffer capacity should stay the same,
as the other subscriber still has not freed its buffer.
- The other subscriber receives one message.
- The available buffer capacity should increase by 1.
- One subscription goes out of scope.
- The available buffer capacity should not change.
*/
TEST(TestIntraProcessManager, lowest_available_capacity) {
using IntraProcessManagerT = rclcpp::experimental::IntraProcessManager;
using MessageT = rcl_interfaces::msg::Log;
using PublisherT = rclcpp::mock::Publisher<MessageT>;
using SubscriptionIntraProcessT = rclcpp::experimental::mock::SubscriptionIntraProcess<MessageT>;
constexpr auto history_depth = 10u;
auto ipm = std::make_shared<IntraProcessManagerT>();
auto p1 = std::make_shared<PublisherT>(rclcpp::QoS(history_depth).best_effort());
auto s1 = std::make_shared<SubscriptionIntraProcessT>(rclcpp::QoS(history_depth).best_effort());
auto s2 = std::make_shared<SubscriptionIntraProcessT>(rclcpp::QoS(history_depth).best_effort());
auto p1_id = ipm->add_publisher(p1);
p1->set_intra_process_manager(p1_id, ipm);
auto c1 = ipm->lowest_available_capacity(p1_id);
ASSERT_LE(0u, c1);
auto s1_id = ipm->add_subscription(s1);
auto s2_id = ipm->add_subscription(s2);
bool unique_ids = s1_id != s2_id && p1_id != s1_id;
ASSERT_TRUE(unique_ids);
size_t p1_subs = ipm->get_subscription_count(p1_id);
size_t non_existing_pub_subs = ipm->get_subscription_count(42);
ASSERT_EQ(2u, p1_subs);
ASSERT_EQ(0u, non_existing_pub_subs);
c1 = ipm->lowest_available_capacity(p1_id);
auto non_existing_pub_c = ipm->lowest_available_capacity(42);
ASSERT_EQ(history_depth, c1);
ASSERT_EQ(0u, non_existing_pub_c);
auto unique_msg = std::make_unique<MessageT>();
p1->publish(std::move(unique_msg));
c1 = ipm->lowest_available_capacity(p1_id);
ASSERT_EQ(history_depth - 1u, c1);
unique_msg = std::make_unique<MessageT>();
p1->publish(std::move(unique_msg));
c1 = ipm->lowest_available_capacity(p1_id);
ASSERT_EQ(history_depth - 2u, c1);
s1->pop();
c1 = ipm->lowest_available_capacity(p1_id);
ASSERT_EQ(history_depth - 2u, c1);
s2->pop();
c1 = ipm->lowest_available_capacity(p1_id);
ASSERT_EQ(history_depth - 1u, c1);
ipm->get_subscription_intra_process(s1_id).reset();
c1 = ipm->lowest_available_capacity(p1_id);
ASSERT_EQ(history_depth - 1u, c1);
}

View File

@@ -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());
}
{

View File

@@ -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);

View File

@@ -629,41 +629,6 @@ TEST_P(TestPublisherWaitForAllAcked, check_wait_for_all_acked_with_QosPolicy) {
EXPECT_TRUE(pub->wait_for_all_acked(std::chrono::milliseconds(6000)));
}
TEST_F(TestPublisher, lowest_available_ipm_capacity) {
constexpr auto history_depth = 10u;
initialize(rclcpp::NodeOptions().use_intra_process_comms(true));
rclcpp::PublisherOptionsWithAllocator<std::allocator<void>> options_ipm_disabled;
options_ipm_disabled.use_intra_process_comm = rclcpp::IntraProcessSetting::Disable;
rclcpp::PublisherOptionsWithAllocator<std::allocator<void>> options_ipm_enabled;
options_ipm_enabled.use_intra_process_comm = rclcpp::IntraProcessSetting::Enable;
auto do_nothing = [](std::shared_ptr<const test_msgs::msg::Strings>) {};
auto pub_ipm_disabled = node->create_publisher<test_msgs::msg::Strings>(
"topic", history_depth,
options_ipm_disabled);
auto pub_ipm_enabled = node->create_publisher<test_msgs::msg::Strings>(
"topic", history_depth,
options_ipm_enabled);
auto sub = node->create_subscription<test_msgs::msg::Strings>(
"topic",
history_depth,
do_nothing);
ASSERT_EQ(1, pub_ipm_enabled->get_intra_process_subscription_count());
ASSERT_EQ(0, pub_ipm_disabled->lowest_available_ipm_capacity());
ASSERT_EQ(history_depth, pub_ipm_enabled->lowest_available_ipm_capacity());
auto msg = std::make_shared<test_msgs::msg::Strings>();
ASSERT_NO_THROW(pub_ipm_disabled->publish(*msg));
ASSERT_NO_THROW(pub_ipm_enabled->publish(*msg));
ASSERT_EQ(0, pub_ipm_disabled->lowest_available_ipm_capacity());
ASSERT_EQ(history_depth - 1u, pub_ipm_enabled->lowest_available_ipm_capacity());
}
INSTANTIATE_TEST_SUITE_P(
TestWaitForAllAckedWithParm,
TestPublisherWaitForAllAcked,

View File

@@ -152,33 +152,54 @@ TEST_F(TestPublisher, conversion_exception_is_passed_up) {
}
}
using UseTakeSharedMethod = bool;
class TestPublisherFixture
: public TestPublisher,
public ::testing::WithParamInterface<UseTakeSharedMethod>
{
};
/*
* Testing that publisher sends type adapted types and ROS message types with intra proccess communications.
*/
TEST_F(
TestPublisher,
TEST_P(
TestPublisherFixture,
check_type_adapted_message_is_sent_and_received_intra_process) {
using StringTypeAdapter = rclcpp::TypeAdapter<std::string, rclcpp::msg::String>;
const std::string message_data = "Message Data";
const std::string topic_name = "topic_name";
bool is_received;
auto callback =
[message_data, &is_received](
const rclcpp::msg::String::ConstSharedPtr msg,
const rclcpp::MessageInfo & message_info
) -> void
{
is_received = true;
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
ASSERT_TRUE(message_info.get_rmw_message_info().from_intra_process);
};
auto node = rclcpp::Node::make_shared(
"test_intra_process",
rclcpp::NodeOptions().use_intra_process_comms(true));
auto pub = node->create_publisher<StringTypeAdapter>(topic_name, 10);
auto sub = node->create_subscription<rclcpp::msg::String>(topic_name, 1, callback);
rclcpp::Subscription<rclcpp::msg::String>::SharedPtr sub;
if (GetParam()) {
auto callback =
[message_data, &is_received](
const rclcpp::msg::String::ConstSharedPtr msg,
const rclcpp::MessageInfo & message_info
) -> void
{
is_received = true;
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
ASSERT_TRUE(message_info.get_rmw_message_info().from_intra_process);
};
sub = node->create_subscription<rclcpp::msg::String>(topic_name, 1, callback);
} else {
auto callback_unique =
[message_data, &is_received](
rclcpp::msg::String::UniquePtr msg,
const rclcpp::MessageInfo & message_info
) -> void
{
is_received = true;
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
ASSERT_TRUE(message_info.get_rmw_message_info().from_intra_process);
};
sub = node->create_subscription<rclcpp::msg::String>(topic_name, 1, callback_unique);
}
auto wait_for_message_to_be_received = [&is_received, &node]() {
rclcpp::executors::SingleThreadedExecutor executor;
@@ -239,6 +260,14 @@ TEST_F(
}
}
INSTANTIATE_TEST_SUITE_P(
TestPublisherFixtureWithParam,
TestPublisherFixture,
::testing::Values(
true, // use take shared method
false // not use take shared method
));
/*
* Testing that publisher sends type adapted types and ROS message types with inter proccess communications.
*/

View File

@@ -18,10 +18,24 @@
#include "rclcpp/rate.hpp"
class TestRate : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
/*
Basic tests for the Rate and WallRate classes.
*/
TEST(TestRate, rate_basics) {
TEST_F(TestRate, rate_basics) {
auto period = std::chrono::milliseconds(1000);
auto offset = std::chrono::milliseconds(500);
auto epsilon = std::chrono::milliseconds(100);
@@ -61,7 +75,7 @@ TEST(TestRate, rate_basics) {
ASSERT_TRUE(epsilon > delta);
}
TEST(TestRate, wall_rate_basics) {
TEST_F(TestRate, wall_rate_basics) {
auto period = std::chrono::milliseconds(100);
auto offset = std::chrono::milliseconds(50);
auto epsilon = std::chrono::milliseconds(1);
@@ -101,7 +115,7 @@ TEST(TestRate, wall_rate_basics) {
EXPECT_GT(epsilon, delta);
}
TEST(TestRate, from_double) {
TEST_F(TestRate, from_double) {
{
rclcpp::WallRate rate(1.0);
EXPECT_EQ(std::chrono::seconds(1), rate.period());

View File

@@ -70,7 +70,7 @@ TEST_F(TestRosoutSubscription, test_rosoutsubscription_getchild) {
// before calling get_child of Logger
{
RCLCPP_INFO(
rclcpp::get_logger(logger_name), "%s", this->rosout_msg_data.c_str());
rclcpp::get_logger(logger_name), this->rosout_msg_data.c_str());
auto future = received_msg_promise.get_future();
auto return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::TIMEOUT, return_code);
@@ -83,7 +83,7 @@ TEST_F(TestRosoutSubscription, test_rosoutsubscription_getchild) {
// after calling get_child of Logger
// 1. use child_logger directly
{
RCLCPP_INFO(child_logger, "%s", this->rosout_msg_data.c_str());
RCLCPP_INFO(child_logger, this->rosout_msg_data.c_str());
auto future = received_msg_promise.get_future();
auto return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
@@ -93,7 +93,7 @@ TEST_F(TestRosoutSubscription, test_rosoutsubscription_getchild) {
// 2. use rclcpp::get_logger
{
RCLCPP_INFO(rclcpp::get_logger(logger_name), "%s", this->rosout_msg_data.c_str());
RCLCPP_INFO(rclcpp::get_logger(logger_name), this->rosout_msg_data.c_str());
auto future = received_msg_promise.get_future();
auto return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
@@ -104,7 +104,7 @@ TEST_F(TestRosoutSubscription, test_rosoutsubscription_getchild) {
// `child_logger` is end of life, there is no sublogger
{
RCLCPP_INFO(rclcpp::get_logger(logger_name), "%s", this->rosout_msg_data.c_str());
RCLCPP_INFO(rclcpp::get_logger(logger_name), this->rosout_msg_data.c_str());
auto future = received_msg_promise.get_future();
auto return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::TIMEOUT, return_code);
@@ -119,7 +119,7 @@ TEST_F(TestRosoutSubscription, test_rosoutsubscription_parent_log) {
rclcpp::Logger logger = this->node->get_logger();
ASSERT_EQ(logger.get_name(), logger_name);
RCLCPP_INFO(logger, "%s", this->rosout_msg_data.c_str());
RCLCPP_INFO(logger, this->rosout_msg_data.c_str());
auto future = received_msg_promise.get_future();
auto return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
@@ -133,14 +133,14 @@ TEST_F(TestRosoutSubscription, test_rosoutsubscription_child_log) {
this->rosout_msg_name = logger_name;
rclcpp::Logger logger = this->node->get_logger();
RCLCPP_INFO(logger, "%s", this->rosout_msg_data.c_str());
RCLCPP_INFO(logger, this->rosout_msg_data.c_str());
auto future = received_msg_promise.get_future();
auto return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::TIMEOUT, return_code);
received_msg_promise = {};
logger = this->node->get_logger().get_child("child1");
RCLCPP_INFO(logger, "%s", this->rosout_msg_data.c_str());
RCLCPP_INFO(logger, this->rosout_msg_data.c_str());
future = received_msg_promise.get_future();
return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
@@ -148,14 +148,14 @@ TEST_F(TestRosoutSubscription, test_rosoutsubscription_child_log) {
received_msg_promise = {};
logger = this->node->get_logger().get_child("child2");
RCLCPP_INFO(logger, "%s", this->rosout_msg_data.c_str());
RCLCPP_INFO(logger, this->rosout_msg_data.c_str());
future = received_msg_promise.get_future();
return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::TIMEOUT, return_code);
received_msg_promise = {};
this->rosout_msg_name = "ns.test_rosout_subscription.child2";
RCLCPP_INFO(logger, "%s", this->rosout_msg_data.c_str());
RCLCPP_INFO(logger, this->rosout_msg_data.c_str());
future = received_msg_promise.get_future();
return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
@@ -171,7 +171,7 @@ TEST_F(TestRosoutSubscription, test_rosoutsubscription_getchild_hierarchy) {
rclcpp::Logger grandchild_logger =
this->node->get_logger().get_child("child").get_child("grandchild");
ASSERT_EQ(grandchild_logger.get_name(), logger_name);
RCLCPP_INFO(grandchild_logger, "%s", this->rosout_msg_data.c_str());
RCLCPP_INFO(grandchild_logger, this->rosout_msg_data.c_str());
auto future = received_msg_promise.get_future();
auto return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);

View File

@@ -313,13 +313,13 @@ TEST_F(TestSubscription, take) {
}
test_msgs::msg::Empty msg;
rclcpp::MessageInfo msg_info;
bool message_received = false;
bool message_recieved = false;
auto start = std::chrono::steady_clock::now();
do {
message_received = sub->take(msg, msg_info);
message_recieved = sub->take(msg, msg_info);
std::this_thread::sleep_for(100ms);
} while (!message_received && std::chrono::steady_clock::now() - start < 10s);
EXPECT_TRUE(message_received);
} while (!message_recieved && std::chrono::steady_clock::now() - start < 10s);
EXPECT_TRUE(message_recieved);
}
// TODO(wjwwood): figure out a good way to test the intra-process exclusion behavior.
}
@@ -350,13 +350,13 @@ TEST_F(TestSubscription, take_serialized) {
}
std::shared_ptr<rclcpp::SerializedMessage> msg = sub->create_serialized_message();
rclcpp::MessageInfo msg_info;
bool message_received = false;
bool message_recieved = false;
auto start = std::chrono::steady_clock::now();
do {
message_received = sub->take_serialized(*msg, msg_info);
message_recieved = sub->take_serialized(*msg, msg_info);
std::this_thread::sleep_for(100ms);
} while (!message_received && std::chrono::steady_clock::now() - start < 10s);
EXPECT_TRUE(message_received);
} while (!message_recieved && std::chrono::steady_clock::now() - start < 10s);
EXPECT_TRUE(message_recieved);
}
}

View File

@@ -305,7 +305,7 @@ TEST_F(TestTimeSource, clock) {
trigger_clock_changes(node, ros_clock, false);
// Even now that we've received a message, ROS time should still not be active since the
// Even now that we've recieved 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());

View File

@@ -3,16 +3,19 @@ Changelog for package rclcpp_action
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
21.3.0 (2023-06-12)
21.0.5 (2024-02-07)
-------------------
21.2.0 (2023-06-07)
21.0.4 (2023-11-17)
-------------------
21.1.1 (2023-05-11)
21.0.3 (2023-09-08)
-------------------
21.1.0 (2023-04-27)
21.0.2 (2023-07-14)
-------------------
21.0.1 (2023-05-11)
-------------------
21.0.0 (2023-04-18)

View File

@@ -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.3.0</version>
<version>21.0.5</version>
<description>Adds action APIs for C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -2,16 +2,23 @@
Changelog for package rclcpp_components
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
21.3.0 (2023-06-12)
21.0.5 (2024-02-07)
-------------------
* Increase the service queue sizes in component_container (`#2381 <https://github.com/ros2/rclcpp/issues/2381>`_)
* Contributors: M. Fatih Cırıt
21.0.4 (2023-11-17)
-------------------
* Add missing header required by the rclcpp::NodeOptions type (`#2325 <https://github.com/ros2/rclcpp/issues/2325>`_)
* Contributors: Ignacio Vizzo
21.0.3 (2023-09-08)
-------------------
21.2.0 (2023-06-07)
21.0.2 (2023-07-14)
-------------------
21.1.1 (2023-05-11)
-------------------
21.1.0 (2023-04-27)
21.0.1 (2023-05-11)
-------------------
21.0.0 (2023-04-18)

View File

@@ -15,6 +15,7 @@
#ifndef RCLCPP_COMPONENTS__NODE_FACTORY_HPP__
#define RCLCPP_COMPONENTS__NODE_FACTORY_HPP__
#include "rclcpp/node_options.hpp"
#include "rclcpp_components/node_instance_wrapper.hpp"
namespace rclcpp_components

View File

@@ -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.3.0</version>
<version>21.0.5</version>
<description>Package containing tools for dynamically loadable components</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -39,10 +39,12 @@ ComponentManager::ComponentManager(
{
loadNode_srv_ = create_service<LoadNode>(
"~/_container/load_node",
std::bind(&ComponentManager::on_load_node, this, _1, _2, _3));
std::bind(&ComponentManager::on_load_node, this, _1, _2, _3),
rclcpp::ServicesQoS().keep_last(200));
unloadNode_srv_ = create_service<UnloadNode>(
"~/_container/unload_node",
std::bind(&ComponentManager::on_unload_node, this, _1, _2, _3));
std::bind(&ComponentManager::on_unload_node, this, _1, _2, _3),
rclcpp::ServicesQoS().keep_last(200));
listNodes_srv_ = create_service<ListNodes>(
"~/_container/list_nodes",
std::bind(&ComponentManager::on_list_nodes, this, _1, _2, _3));

View File

@@ -3,16 +3,22 @@ Changelog for package rclcpp_lifecycle
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
21.3.0 (2023-06-12)
21.0.5 (2024-02-07)
-------------------
21.2.0 (2023-06-07)
21.0.4 (2023-11-17)
-------------------
21.1.1 (2023-05-11)
21.0.3 (2023-09-08)
-------------------
* Switch lifecycle to use the RCLCPP macros. (`#2244 <https://github.com/ros2/rclcpp/issues/2244>`_)
* Add new node interface TypeDescriptionsInterface to provide GetTypeDescription service (`#2236 <https://github.com/ros2/rclcpp/issues/2236>`_)
* Contributors: Emerson Knapp
21.0.2 (2023-07-14)
-------------------
21.1.0 (2023-04-27)
21.0.1 (2023-05-11)
-------------------
21.0.0 (2023-04-18)

View File

@@ -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

View File

@@ -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.3.0</version>
<version>21.0.5</version>
<description>Package containing a prototype for lifecycle implementation</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -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"
@@ -115,7 +116,11 @@ LifecycleNode::LifecycleNode(
)),
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_logging_,
node_parameters_,
node_services_))
{
impl_->init(enable_communication_interface);
@@ -474,6 +479,12 @@ LifecycleNode::get_node_services_interface()
return node_services_;
}
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr
LifecycleNode::get_node_type_descriptions_interface()
{
return impl_->get_node_type_descriptions_interface();
}
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr
LifecycleNode::get_node_parameters_interface()
{

View File

@@ -29,7 +29,9 @@
#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/node_interfaces/node_type_descriptions.hpp"
#include "rclcpp_lifecycle/node_interfaces/lifecycle_node_interface.hpp"
@@ -50,9 +52,17 @@ namespace rclcpp_lifecycle
LifecycleNode::LifecycleNodeInterfaceImpl::LifecycleNodeInterfaceImpl(
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> node_base_interface,
std::shared_ptr<rclcpp::node_interfaces::NodeLoggingInterface> node_logging_interface,
std::shared_ptr<rclcpp::node_interfaces::NodeParametersInterface> node_parameters_interface,
std::shared_ptr<rclcpp::node_interfaces::NodeServicesInterface> node_services_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),
node_type_descriptions_(new rclcpp::node_interfaces::NodeTypeDescriptions(
node_base_interface,
node_logging_interface,
node_parameters_interface,
node_services_interface))
{
}
@@ -65,8 +75,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 +408,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 +422,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 +455,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 +471,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 +482,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 +512,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;
}
}
@@ -581,4 +602,10 @@ LifecycleNode::LifecycleNodeInterfaceImpl::on_deactivate() const
}
}
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr
LifecycleNode::LifecycleNodeInterfaceImpl::get_node_type_descriptions_interface()
{
return node_type_descriptions_;
}
} // namespace rclcpp_lifecycle

View File

@@ -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,6 +53,8 @@ class LifecycleNode::LifecycleNodeInterfaceImpl final
public:
LifecycleNodeInterfaceImpl(
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> node_base_interface,
std::shared_ptr<rclcpp::node_interfaces::NodeLoggingInterface> node_logging_interface,
std::shared_ptr<rclcpp::node_interfaces::NodeParametersInterface> node_parameters_interface,
std::shared_ptr<rclcpp::node_interfaces::NodeServicesInterface> node_services_interface);
~LifecycleNodeInterfaceImpl();
@@ -102,6 +105,9 @@ public:
void
add_timer_handle(std::shared_ptr<rclcpp::TimerBase> timer);
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr
get_node_type_descriptions_interface();
private:
RCLCPP_DISABLE_COPY(LifecycleNodeInterfaceImpl)
@@ -152,6 +158,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 +170,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_;
@@ -172,6 +180,9 @@ private:
// to controllable things
std::vector<std::weak_ptr<rclcpp_lifecycle::ManagedEntityInterface>> weak_managed_entities_;
std::vector<std::weak_ptr<rclcpp::TimerBase>> weak_timers_;
// Backported members hidden in impl
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr node_type_descriptions_;
};
} // namespace rclcpp_lifecycle

View File

@@ -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) {