Compare commits

..

98 Commits
iron ... 25.0.0

Author SHA1 Message Date
Chris Lalancette
5d2b32b5c3 25.0.0 2023-12-26 17:17:23 +00:00
Chris Lalancette
21f8a22311 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-12-26 17:17:15 +00:00
DensoADAS
2bb1dc2c71 Updated GenericSubscription to AnySubscriptionCallback (#1928)
* added rclcpp::SerializedMessage support for AnySubscriptionCallback

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>
Signed-off-by: Joshua Hampp <j.hampp@eu.denso.com>

* using AnySubscription callback for generic subscriptiion

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>
Signed-off-by: Joshua Hampp <j.hampp@eu.denso.com>

* updated tests

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>
Signed-off-by: Joshua Hampp <j.hampp@eu.denso.com>

* Remove comment

Signed-off-by: Joshua Hampp <j.hampp@eu.denso.com>

---------

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>
Signed-off-by: Joshua Hampp <j.hampp@eu.denso.com>
Co-authored-by: Joshua Hampp <j.hampp@denso-adas.de>
Co-authored-by: Jacob Perron <jacob@openrobotics.org>
2023-12-19 08:35:13 -08:00
Chen Lihui
d9b2744057 make type support helper supported for service (#2209)
* make type support helper supported for service and action as well

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* not to use template and only add the necessary service type currently

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update comment

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* add deprecated cycle for `get_typesupport_handle`

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

---------

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2023-12-11 17:33:28 -08:00
Lucas Wendland
a19ad2134b Adding QoS to subscription options (#2323)
* Adding QoS to subscription options

Signed-off-by: CursedRock17 <mtglucas1@gmail.com>
2023-12-01 10:01:27 -05:00
Chris Lalancette
26f6efa840 Switch to target_link_libraries. (#2374)
That way we can hide more of the implementation by using
the PRIVATE keyword.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-11-27 16:39:20 -05:00
Daisuke Nishimatsu
d08d9cf5ff feat(rclcpp_components): support events executor in node main template (#2366)
Signed-off-by: wep21 <daisuke.nishimatsu1021@gmail.com>
2023-11-17 08:20:30 -05:00
Chen Lihui
2446fd000b aligh with rcl that a rosout publisher of a node might not exist (#2357)
* aligh with rcl

* keep same behavior with rclpy

1. to not throw exception durning rcl_logging_rosout_remove_sublogger
2. reset error message for RCL_RET_NOT_FOUND

* test for a node with rosout disabled

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2023-11-15 10:44:25 -05:00
mauropasse
411dbe8212 Fix data race in EventHandlerBase (#2349)
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>
2023-11-13 21:24:07 -05:00
Chris Lalancette
de841d9c8b Support users holding onto shared pointers in the message memory pool (#2336)
* Support users holding onto shared pointers in the message memory pool

Before this commit, the MessageMemoryPool would actually
reuse messages in the pool, even if the user had taken
additional shared_ptr copies.

This commit fixes things so that we properly handle that situation.  In particular, 
we allocate memory during class initialization, and delete
it during destruction.  We then run the constructor when
we hand the pointer out, and the destructor (only) when
we return it to the pool.  This keeps things consistent.
We also add in locks, since in a multi-threaded scenario we need
to protect against multiple threads accessing the pool
at the same time.

With this in place, things work as expected when users hold
shared_ptr copies.  We also add in a test for this situation.

One note about performance: this update preserves the
"no-allocations-at-runtime" aspect of the MessagePool.  However,
there are some tradeoffs with CPU time here, particularly with
very large message pools.  This could probably be optimized
further to do less work when trying to add items back to the
free_list, but I view that as a further enhancement.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-11-13 15:32:42 -05:00
M. Fatih Cırıt
9c098e544e fix(rclcpp_components): increase the service queue sizes in component_container (#2363)
* fix(rclcpp_components): increase the service queue sizes in component_container

Signed-off-by: M. Fatih Cırıt <mfc@leodrive.ai>
2023-11-09 15:09:18 -05:00
Chris Lalancette
0f331f90a9 24.0.0 2023-11-06 17:36:49 +00:00
Chris Lalancette
620fcf1e05 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-11-06 17:36:40 +00:00
Zard-C
d407a5e331 fix (signal_handler.hpp): spelling (#2356)
Signed-off-by: Zard-C <patrick.zhang5233@gmail.com>
2023-11-05 14:28:17 -05:00
Chris Lalancette
7f411371b3 Updates to not use std::move in some places. (#2353)
gcc 13.1.1 complains that these uses inhibit copy elision.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-11-05 14:27:40 -05:00
Tomoya Fujita
76e2b2677b rclcpp::Time::max() clock type support. (#2352)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-11-04 09:08:11 -07:00
Lucas Wendland
5049c45f85 Serialized Messages with Topic Statistics (#2274)
Signed-off-by: CursedRock17 <mtglucas1@gmail.com>
2023-11-03 15:06:25 -07:00
Michael Carroll
4691063a61 Add a custom deleter when constructing rcl_service_t (#2351)
* Add a custom deleter when constructing rcl_service_t

In the type description service construction, we were previously passing
the shared_ptr to the rcl_service_t with the assumption that
rclcpp::Service would do the clean up.  This was an incorrect
assumption, and so I have added a custom deleter to fini the service and
delete when the shared_ptr is cleaned up.

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>
2023-11-03 08:59:06 -04:00
Chris Lalancette
f294488e17 Disable the loaned messages inside the executor. (#2335)
* 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>
2023-11-02 18:29:12 -04:00
Michael Orlov
8a02e3934c Use message_info in SubscriptionTopicStatistics instead of typed message (#2337)
* Use message_info in SubscriptionTopicStatistics instead of typed message

- Untemplatize the rclcpp::topic_statistics::SubscriptionTopicStatistics
class. Now we will be using message_info instead of typed deserialized
messages in the handle_message callbacks.

* Fix test_receive_stats_include_window_reset by using publisher emulator

- Emulate publishing messages by directly calling
rclcpp::Subscription::handle_message(msg_shared_ptr, message_info) and
settling up needed message_info.source_timestamp

Signed-off-by: Michael Orlov <michael.orlov@apex.ai>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-11-02 13:26:33 -04:00
Jiaqi Li
fff009a751 Add missing 'enable_rosout' comments (#2345)
Signed-off-by: Jiaqi Li <ljq0831@qq.com>
2023-10-31 00:21:28 -07:00
Michael Carroll
2204e44305 Adjust rclcpp usage of type description service (#2344)
Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>
2023-10-30 19:24:24 +00:00
Tomoya Fujita
fcbe64cff4 address rate related flaky tests. (#2329)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-10-26 00:08:18 -07:00
Chris Lalancette
c366e531fa Fixes pointed out by the clang analyzer. (#2339)
1. Remove the default Logger copy constructor without copy
assignment (rule of three -> rule of zero).
2. Remove an unnecessary capture in a lambda.
3. Mark a variable unused.
4. Mark a method as override.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-10-23 11:10:18 -05:00
Alexey Merzlyakov
5ffc963e1a Remove useless ROSRate class (#2326)
Signed-off-by: Alexey Merzlyakov <alexey.merzlyakov@samsung.com>
2023-10-16 09:38:38 -04:00
Chris Lalancette
7f7ffcf6ed Fix rclcpp_lifecycle inclusion on Windows. (#2331)
The comment in the commit explains this clearly, but
on Windows ERROR is a macro.  The reuse of it, even
as an enum, causes compilation errors on downstream
users.  Push the macro and undefine it so downstream
consumers can freely include it.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-10-10 13:25:55 -04:00
Chris Lalancette
13abc1beed 23.2.0 2023-10-09 15:31:54 +00:00
Chris Lalancette
e77c1fe550 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-10-09 15:31:47 +00:00
Minju, Lee
00b9d0a018 add clients & services count (#2072)
* add clients & services count

* add count clients,services tests

Signed-off-by: leeminju531 <dlalswn531@naver.com>
2023-10-09 10:36:00 -04:00
Tomoya Fujita
77c7aaf917 remove invalid sized allocation test for SerializedMessage. (#2330)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-10-06 15:15:34 -07:00
Steve Macenski
9019a8d9b7 Adding API to copy all parameters from one node to another (#2304)
Signed-off-by: stevemacenski <stevenmacenski@gmail.com>
2023-10-05 13:00:16 -07:00
Chris Lalancette
0644f220a2 23.1.0 2023-10-04 13:09:05 +00:00
Chris Lalancette
32438a6a67 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-10-04 13:08:56 +00:00
Ignacio Vizzo
d6bd8baac5 Add missing header required by the rclcpp::NodeOptions type (#2324)
Signed-off-by: Ignacio Vizzo <ignacio@dexory.com>
2023-10-04 08:18:21 -04:00
Chris Lalancette
623c3eb874 Add locking to protect the TimeSource::NodeState::node_base_ (#2320)
We need this because it is possible for one thread to
be handling the on_parameter_event callback while another
one is detaching the node.  This lock will protect that
from happening.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-10-03 14:16:49 -04:00
Tully Foote
7c1143dc15 Update SignalHandler get_global_signal_handler to avoid complex types in static memory (#2316)
* 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>
2023-09-29 16:13:43 -07:00
Lucas Wendland
9ff864c6ae Removing Old Connext Tests (#2313)
* Removing Old Connext Tests

Signed-off-by: CursedRock17 <mtglucas1@gmail.com>
2023-09-28 08:29:47 -04:00
Lucas Wendland
13182b5aad Documentation for list_parameters (#2315)
* list_parameters documentation

Signed-off-by: CursedRock17 <mtglucas1@gmail.com>
2023-09-27 17:14:53 -04:00
Tomoya Fujita
9284d7cefa Decouple rosout publisher init from node init. (#2174)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-09-21 18:44:13 -07:00
Minju, Lee
c42745c5ba fix the depth to relative in list_parameters (#2300)
* fix the depth to relative in list_parameters

Signed-off-by: leeminju531 <dlalswn531@naver.com>
2023-09-18 17:13:11 -04:00
Chris Lalancette
ea31f94eb4 23.0.0 2023-09-08 20:47:00 +00:00
Chris Lalancette
f496291e81 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-09-08 20:46:51 +00:00
Chris Lalancette
dd6fad6d42 Fix the return type of Rate::period. (#2301)
In a recent commit (bc435776a2),
we reworked how the Rate class worked so it could be
used with ROS time as well.  Unfortunately, we also
accidentally broke the API of it by changing the return
type of Rate::period to a Duration instead of a
std::chrono::nanoseconds .  Put this back to a std::chrono::nanoseconds;
if we want to change it to a Duration, we'll have to
add a new method and deprecate this one.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-09-08 16:40:09 -04:00
Christophe Bedard
38734d769a Update API docs links in package READMEs (#2302)
Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
2023-09-08 13:59:15 -04:00
jmachowinski
e103b8d37e fix(ClientGoalHandle): Made mutex recursive to prevent deadlocks (#2267)
* fix(ClientGoalHandle): Made mutex recursive to prevent deadlocks

This prevents deadlocks in cases, were e.g. get_status() would
be called on the handle in a callback of the handle.

* test(rclcpp_action): Added test for deadlocks during access of a goal handle

This test checks, if the code deadlocks, if methods on the goal handle are
called from the callbacks.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-09-07 17:37:35 -04:00
Chris Lalancette
253d395d4e Cleanup flaky timers_manager tests. (#2299)
* Cleanup flaky timers_manager tests.

The timers_manager tests were relying too heavily on
specific timings; this caused them to be flaky on the
buildfarm, particularly on Windows.

Here, we increase the timeouts, and remove one test which
just relies too heavily on specific timeouts.  This should
make this test much less flaky on the buildfarm.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-09-07 15:17:16 -04:00
Chris Lalancette
d5e5141b3d 22.2.0 2023-09-07 14:59:44 +00:00
Chris Lalancette
a0148dfd5d Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-09-07 14:59:26 +00:00
Chen Lihui
5e152d77d8 Topic correct typeadapter deduction (#2294)
* fix TypeAdapter deduction

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2023-09-06 10:24:51 -04:00
AiVerisimilitude
fa732b9ee8 Fix C++20 allocator construct deprecation (#2292)
Signed-off-by: Guilherme Rodrigues <guilherme.rodrigues@ait.ac.at>
2023-09-01 17:17:00 -07:00
Alexey Merzlyakov
bc435776a2 Make Rate to select the clock to work with (#2123)
* Make Rate to select the clock to work with
Add ROSRate respective with ROS time

* Make GenericRate class to be deprecated

* Adjust test cases for new rates

is_steady() to be deprecated

Signed-off-by: Alexey Merzlyakov <alexey.merzlyakov@samsung.com>
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
2023-08-31 15:50:40 -04:00
Jiaqi Li
43cf0be15c Correct the position of a comment. (#2290)
Signed-off-by: Jiaqi Li <ljq0831@qq.com>
2023-08-29 13:22:51 -04:00
Chris Lalancette
fd58bddb05 Remove unnecessary lambda captures in the tests. (#2289)
* Remove unnecessary lambda captures in the tests.

This was pointed out by compiling with clang.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-08-28 14:17:27 -04:00
Tomoya Fujita
e7f06398db add logger level service to lifecycle node. (#2277)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-08-26 11:38:52 -07:00
Chris Lalancette
ba175922d3 Add rcl_logging_interface as an explicit dependency. (#2284)
It is depended on by rclcpp/src/rclcpp/logger.cpp, but
the dependency was not explicitly declared (it was
being inherited from rcl, I believe).  Fix that here.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-08-23 19:43:54 -04:00
Chris Lalancette
77db1ed25b Revamp list_parameters to be more efficient and easier to read. (#2282)
1. Use constref for the loop variable.
2. Do more work outside of the loop.
3. Skip doing unnecessary work where we can inside the loop.

With this in place, I measured about a 7% performance
improvement over the previous implementation.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-08-23 08:15:44 -04:00
Chris Lalancette
403f305b15 Fix a typo in a comment. (#2283)
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-08-22 15:22:01 -07:00
Tomoya Fujita
fd229d72ff doc fix: call canceled only after goal state is in canceling. (#2266)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-08-21 16:04:49 -04:00
Chris Lalancette
89f0afe9bc 22.1.0 2023-08-21 14:52:05 +00:00
Chris Lalancette
a4db4c57a6 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-08-21 14:51:57 +00:00
Tomoya Fujita
fbe8f28cd1 Do not crash Executor when send_response fails due to client failure. (#2276)
* 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>
2023-08-18 09:15:04 -07:00
Lucas Wendland
65f0b70d4a Adding Custom Unknown Type Error (#2272)
Signed-off-by: CursedRock17 <mtglucas1@gmail.com>
Co-authored-by: Christophe Bedard <bedard.christophe@gmail.com>
2023-08-15 15:21:33 -07:00
Emerson Knapp
9b4b3da3d4 Add a pimpl inside rclcpp::Node for future distro backports (#2228)
* Add a pimpl inside rclcpp::Node for future distro backports

Signed-off-by: Emerson Knapp <emerson.b.knapp@gmail.com>
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
2023-08-10 08:31:05 -04:00
Chris Lalancette
cd0440f1a5 Remove an unused variable from the events executor tests. (#2270)
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-08-09 16:56:01 -04:00
Tony Najjar
a17d26b20a Add spin_all shortcut (#2246)
Signed-off-by: Tony Najjar <tony.najjar@logivations.com>
2023-08-08 16:38:13 -05:00
Lucas Wendland
e2965831d5 Adding Missing Group Exceptions (#2256)
* Adding Missing Group Exceptions

Signed-off-by: CursedRock17 <mtglucas1@gmail.com>
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-08-04 16:25:26 -04:00
Luca Della Vedova
ea29c142af Change associated clocks storage to unordered_set (#2257)
Signed-off-by: Luca Della Vedova <lucadv@intrinsic.ai>
2023-08-03 08:43:04 -04:00
Tomoya Fujita
5d6e5fa766 associated clocks should be protected by mutex. (#2255)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-08-01 22:43:02 -07:00
Christophe Bedard
22a954e1b0 Instrument loaned message publication code path (#2240)
Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
2023-07-21 11:26:42 -07:00
Chris Lalancette
c0d72c3ee0 Stop using constref signature of benchmark DoNotOptimize. (#2238)
* Stop using constref signature of benchmark DoNotOptimize.

Newer versions of google benchmark (1.8.2 in my case) warn
that the compiler may optimize away the DoNotOptimize calls
when using the constref version.  Get away from that here
by explicitly *not* calling the constref version, casting
where necessary.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-07-18 10:18:22 -04:00
Chris Lalancette
6e97990a32 22.0.0 2023-07-11 19:48:37 +00:00
Chris Lalancette
4ebc5f61d8 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-07-11 19:48:30 +00:00
Emerson Knapp
a7a9b78fee Implement get_node_type_descriptions_interface for lifecyclenode and add smoke test for it (#2237)
Signed-off-by: Emerson Knapp <emerson.b.knapp@gmail.com>
2023-07-11 08:41:53 -04:00
Chris Lalancette
945d254e32 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>
2023-07-10 15:59:35 -04:00
Emerson Knapp
deebbc3ad6 Add new node interface TypeDescriptionsInterface to provide GetTypeDescription service (#2224)
* TypeDescriptions interface with readonly param configuration

* Add parameter descriptor, to make read only

* example of spinning in thread for get_type_description service

* Add a basic test for the new interface

* Fix tests with new parameter

* Add comments about builtin parameters

Signed-off-by: Emerson Knapp <emerson.b.knapp@gmail.com>
Signed-off-by: William Woodall <william@osrfoundation.org>
2023-07-07 13:10:27 -04:00
Nathan Wiebe Neufeldt
588dba7a70 Move always_false_v to detail namespace (#2232)
Since this is a common idiom, especially under this name, we should
define the `always_false_v` template within a namespace to avoid
conflict with other libraries and user code. This could either be
`rclcpp::detail` if it's intended only for internal use or just `rclcpp`
if it's intended as a public helper. In this PR, I've initially chosen
the former.

Signed-off-by: Nathan Wiebe Neufeldt <nwiebeneufeldt@clearpath.ai>
2023-07-05 16:55:11 -04:00
Chris Lalancette
2e355e4849 Revamp the test_subscription.cpp tests. (#2227)
The original motiviation to do this was a crash during
teardown when using a newer version of gtest.  But while
I was in here, I did a small overall cleanup, including:

1.  Moving code closer to where it is actually used.
2.  Getting rid of unused 'using' statements.
3.  Adding in missing includes.
4.  Properly tearing down and recreating the rclcpp
    context during test teardown (this fixed the actual
    bug).
5.  Making class members private where possible.
6.  Renaming class methods to our usual conventions.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-06-26 12:59:56 -04:00
Tomoya Fujita
fe2e0e4c64 warning: comparison of integer expressions of different signedness (#2219)
https://github.com/ros2/rclcpp/pull/2167#issuecomment-1597197552

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-06-22 08:02:27 -07:00
Eloy Briceno
005f6aefe9 Modifies timers API to select autostart state (#2005)
* Modifies timers API to select autostart state

* Removes unnecessary variables

* Adds autostart documentation and expands some timer test

Signed-off-by: Voldivh <eloyabmfcv@gmail.com>
2023-06-21 10:47:14 -04:00
Christopher Wecht
3a64349aec Enable callback group tests for connextdds (#2182)
* Enable callback group tests for connextdds

* Enable executors and event executor tests for connextdds

* Enable qos events tests for connextdds

* Less flaky qos_event tests

Signed-off-by: Christopher Wecht <cwecht@mailbox.org>
2023-06-14 08:33:33 -04:00
Chris Lalancette
3530b0959c 21.3.0 2023-06-12 12:45:11 +00:00
Chris Lalancette
4d12bcbca0 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-06-12 12:45:00 +00:00
Chris Lalancette
1fff79089a Fix up misspellings of "receive". (#2208)
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-06-11 22:48:56 -07:00
Michael Carroll
b3518d12ca Remove flaky stressAddRemoveNode test (#2206)
Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>
2023-06-09 11:18:04 -05:00
Christophe Bedard
4efc05266b Use TRACETOOLS_ prefix for tracepoint-related macros (#2162)
Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
2023-06-08 12:38:49 -05:00
Chris Lalancette
dab9c8acdc 21.2.0 2023-06-07 13:28:18 +00:00
Chris Lalancette
867ad62da2 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-06-07 13:28:05 +00:00
Chen Lihui
f8072f2fa2 remove nolint since ament_cpplint updated for the c++17 header (#2198)
Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2023-05-22 21:22:13 -07:00
DensoADAS
fce021b149 Feature/available capacity of ipm (#2173)
* added available_capacity to get the lowest number of free capacity for intra-process communication for a publisher

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

* added unit tests for available_capacity

Signed-off-by: Joshua Hampp <j.hampp@eu.denso.com>
Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

* fixed typos in comments

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

* Updated warning

Co-authored-by: Alberto Soragna <alberto.soragna@gmail.com>
Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

* returning 0 if ipm is disabled in lowest_available_ipm_capacity

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

* return 0 if no subscribers are present in lowest_available_capacity

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

* updated unit test

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

* update unit test

Signed-off-by: Joshua Hampp <j.hampp@eu.denso.com>

* moved available_capacity to a lambda function to be able to handle subscriptions which went out of scope

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

* updated unit test to check subscriptions which went out of scope

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

---------

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>
Signed-off-by: Joshua Hampp <j.hampp@eu.denso.com>
Co-authored-by: Joshua Hampp <j.hampp@denso-adas.de>
Co-authored-by: Joshua Hampp <j.hampp@eu.denso.com>
Co-authored-by: Alberto Soragna <alberto.soragna@gmail.com>
2023-05-19 19:31:59 +01:00
Alberto Soragna
c4f57a7998 add mutex to protect events_executor current entity collection (#2187)
* add mutex to protect events_executor current entity collection and unit-test

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* be more precise with mutex locks; make stress test less stressfull

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* fix uncrustify error

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

---------

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2023-05-18 14:43:26 +01:00
mauropasse
d7fdb6184c Declare rclcpp callbacks before the rcl entities (#2024)
This is to ensure callbacks are destroyed last
on entities destruction, avoiding the gap in time
in which rmw entities hold a reference to a
destroyed function.

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>
Co-authored-by: Mauro Passerino <mpasserino@irobot.com>
2023-05-15 15:55:08 -04:00
Yadunund
58bcd3b822 21.1.1 2023-05-11 18:59:17 +08:00
Yadunund
26426adda9 Changelog
Signed-off-by: Yadunund <yadunund@openrobotics.org>
2023-05-11 18:58:48 +08:00
Alberto Soragna
6e1fea14e1 Fix race condition in events-executor (#2177)
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>
2023-05-05 09:04:35 -05:00
Øystein Sture
86c77143c9 Add missing stdexcept include (#2186)
Signed-off-by: Øystein Sture <os@skarvtech.com>
2023-05-04 15:48:20 -04:00
Chris Lalancette
b812790ee3 Fix a format-security warning when building with clang (#2171)
In particular, you should never have a "bare" string in a
printf-like call; that could potentially access uninitialized
memory. Instead, make sure to format the string with %s.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-05-01 17:06:55 -04:00
methylDragon
6ca1023ef7 Fix delivered message kind (#2175)
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-05-01 16:56:29 -04:00
Yadunund
77ede02251 21.1.0 2023-04-27 16:53:54 +08:00
136 changed files with 3248 additions and 2487 deletions

View File

@@ -2,56 +2,117 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
21.0.8 (2024-11-08)
25.0.0 (2023-12-26)
-------------------
* associated clocks should be protected by mutex. (`#2258 <https://github.com/ros2/rclcpp/issues/2258>`_)
* Skip client_qos test (`#2658 <https://github.com/ros2/rclcpp/issues/2658>`_)
* Use the same context for the specified node in rclcpp::spin functions. (`#2618 <https://github.com/ros2/rclcpp/issues/2618>`_)
* Contributors: Cristóbal Arroyo, Tomoya Fujita
* Updated GenericSubscription to AnySubscriptionCallback (`#1928 <https://github.com/ros2/rclcpp/issues/1928>`_)
* make type support helper supported for service (`#2209 <https://github.com/ros2/rclcpp/issues/2209>`_)
* Adding QoS to subscription options (`#2323 <https://github.com/ros2/rclcpp/issues/2323>`_)
* Switch to target_link_libraries. (`#2374 <https://github.com/ros2/rclcpp/issues/2374>`_)
* aligh with rcl that a rosout publisher of a node might not exist (`#2357 <https://github.com/ros2/rclcpp/issues/2357>`_)
* Fix data race in EventHandlerBase (`#2349 <https://github.com/ros2/rclcpp/issues/2349>`_)
* Support users holding onto shared pointers in the message memory pool (`#2336 <https://github.com/ros2/rclcpp/issues/2336>`_)
* Contributors: Chen Lihui, Chris Lalancette, DensoADAS, Lucas Wendland, mauropasse
21.0.7 (2024-07-10)
24.0.0 (2023-11-06)
-------------------
* Add test creating two content filter topics with the same topic name (`#2550 <https://github.com/ros2/rclcpp/issues/2550>`_)
* Revise the description of service configure_introspection() (`#2514 <https://github.com/ros2/rclcpp/issues/2514>`_)
* Contributors: Alejandro Hernández Cordero, Barry Xu
* fix (signal_handler.hpp): spelling (`#2356 <https://github.com/ros2/rclcpp/issues/2356>`_)
* Updates to not use std::move in some places. (`#2353 <https://github.com/ros2/rclcpp/issues/2353>`_)
* rclcpp::Time::max() clock type support. (`#2352 <https://github.com/ros2/rclcpp/issues/2352>`_)
* Serialized Messages with Topic Statistics (`#2274 <https://github.com/ros2/rclcpp/issues/2274>`_)
* Add a custom deleter when constructing rcl_service_t (`#2351 <https://github.com/ros2/rclcpp/issues/2351>`_)
* Disable the loaned messages inside the executor. (`#2335 <https://github.com/ros2/rclcpp/issues/2335>`_)
* Use message_info in SubscriptionTopicStatistics instead of typed message (`#2337 <https://github.com/ros2/rclcpp/issues/2337>`_)
* Add missing 'enable_rosout' comments (`#2345 <https://github.com/ros2/rclcpp/issues/2345>`_)
* Adjust rclcpp usage of type description service (`#2344 <https://github.com/ros2/rclcpp/issues/2344>`_)
* address rate related flaky tests. (`#2329 <https://github.com/ros2/rclcpp/issues/2329>`_)
* Fixes pointed out by the clang analyzer. (`#2339 <https://github.com/ros2/rclcpp/issues/2339>`_)
* Remove useless ROSRate class (`#2326 <https://github.com/ros2/rclcpp/issues/2326>`_)
* Contributors: Alexey Merzlyakov, Chris Lalancette, Jiaqi Li, Lucas Wendland, Michael Carroll, Michael Orlov, Tomoya Fujita, Zard-C
21.0.6 (2024-04-19)
23.2.0 (2023-10-09)
-------------------
* address ambiguous auto variable. (`#2486 <https://github.com/ros2/rclcpp/issues/2486>`_)
* Contributors: Tomoya Fujita
* add clients & services count (`#2072 <https://github.com/ros2/rclcpp/issues/2072>`_)
* remove invalid sized allocation test for SerializedMessage. (`#2330 <https://github.com/ros2/rclcpp/issues/2330>`_)
* Adding API to copy all parameters from one node to another (`#2304 <https://github.com/ros2/rclcpp/issues/2304>`_)
* Contributors: Minju, Lee, Steve Macenski, Tomoya Fujita
21.0.5 (2024-02-07)
23.1.0 (2023-10-04)
-------------------
* Fix data race in EventHandlerBase (`#2387 <https://github.com/ros2/rclcpp/issues/2387>`_)
* Contributors: mauropasse
* Add locking to protect the TimeSource::NodeState::node_base\_ (`#2320 <https://github.com/ros2/rclcpp/issues/2320>`_)
* Update SignalHandler get_global_signal_handler to avoid complex types in static memory (`#2316 <https://github.com/ros2/rclcpp/issues/2316>`_)
* Removing Old Connext Tests (`#2313 <https://github.com/ros2/rclcpp/issues/2313>`_)
* Documentation for list_parameters (`#2315 <https://github.com/ros2/rclcpp/issues/2315>`_)
* Decouple rosout publisher init from node init. (`#2174 <https://github.com/ros2/rclcpp/issues/2174>`_)
* fix the depth to relative in list_parameters (`#2300 <https://github.com/ros2/rclcpp/issues/2300>`_)
* Contributors: Chris Lalancette, Lucas Wendland, Minju, Lee, Tomoya Fujita, Tully Foote
21.0.4 (2023-11-17)
23.0.0 (2023-09-08)
-------------------
* 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
* Fix the return type of Rate::period. (`#2301 <https://github.com/ros2/rclcpp/issues/2301>`_)
* Update API docs links in package READMEs (`#2302 <https://github.com/ros2/rclcpp/issues/2302>`_)
* Cleanup flaky timers_manager tests. (`#2299 <https://github.com/ros2/rclcpp/issues/2299>`_)
* Contributors: Chris Lalancette, Christophe Bedard
21.0.3 (2023-09-08)
22.2.0 (2023-09-07)
-------------------
* 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
* Topic correct typeadapter deduction (`#2294 <https://github.com/ros2/rclcpp/issues/2294>`_)
* Fix C++20 allocator construct deprecation (`#2292 <https://github.com/ros2/rclcpp/issues/2292>`_)
* Make Rate to select the clock to work with (`#2123 <https://github.com/ros2/rclcpp/issues/2123>`_)
* Correct the position of a comment. (`#2290 <https://github.com/ros2/rclcpp/issues/2290>`_)
* Remove unnecessary lambda captures in the tests. (`#2289 <https://github.com/ros2/rclcpp/issues/2289>`_)
* Add rcl_logging_interface as an explicit dependency. (`#2284 <https://github.com/ros2/rclcpp/issues/2284>`_)
* Revamp list_parameters to be more efficient and easier to read. (`#2282 <https://github.com/ros2/rclcpp/issues/2282>`_)
* Contributors: AiVerisimilitude, Alexey Merzlyakov, Chen Lihui, Chris Lalancette, Jiaqi Li
21.0.2 (2023-07-14)
22.1.0 (2023-08-21)
-------------------
* 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
* Do not crash Executor when send_response fails due to client failure. (`#2276 <https://github.com/ros2/rclcpp/issues/2276>`_)
* Adding Custom Unknown Type Error (`#2272 <https://github.com/ros2/rclcpp/issues/2272>`_)
* Add a pimpl inside rclcpp::Node for future distro backports (`#2228 <https://github.com/ros2/rclcpp/issues/2228>`_)
* Remove an unused variable from the events executor tests. (`#2270 <https://github.com/ros2/rclcpp/issues/2270>`_)
* Add spin_all shortcut (`#2246 <https://github.com/ros2/rclcpp/issues/2246>`_)
* Adding Missing Group Exceptions (`#2256 <https://github.com/ros2/rclcpp/issues/2256>`_)
* Change associated clocks storage to unordered_set (`#2257 <https://github.com/ros2/rclcpp/issues/2257>`_)
* associated clocks should be protected by mutex. (`#2255 <https://github.com/ros2/rclcpp/issues/2255>`_)
* Instrument loaned message publication code path (`#2240 <https://github.com/ros2/rclcpp/issues/2240>`_)
* Contributors: Chris Lalancette, Christophe Bedard, Emerson Knapp, Luca Della Vedova, Lucas Wendland, Tomoya Fujita, Tony Najjar
21.0.1 (2023-05-11)
22.0.0 (2023-07-11)
-------------------
* Implement get_node_type_descriptions_interface for lifecyclenode and add smoke test for it (`#2237 <https://github.com/ros2/rclcpp/issues/2237>`_)
* Add new node interface TypeDescriptionsInterface to provide GetTypeDescription service (`#2224 <https://github.com/ros2/rclcpp/issues/2224>`_)
* Move always_false_v to detail namespace (`#2232 <https://github.com/ros2/rclcpp/issues/2232>`_)
* Revamp the test_subscription.cpp tests. (`#2227 <https://github.com/ros2/rclcpp/issues/2227>`_)
* warning: comparison of integer expressions of different signedness (`#2219 <https://github.com/ros2/rclcpp/issues/2219>`_)
* Modifies timers API to select autostart state (`#2005 <https://github.com/ros2/rclcpp/issues/2005>`_)
* Enable callback group tests for connextdds (`#2182 <https://github.com/ros2/rclcpp/issues/2182>`_)
* Contributors: Chris Lalancette, Christopher Wecht, Eloy Briceno, Emerson Knapp, Nathan Wiebe Neufeldt, Tomoya Fujita
21.3.0 (2023-06-12)
-------------------
* Fix up misspellings of "receive". (`#2208 <https://github.com/ros2/rclcpp/issues/2208>`_)
* Remove flaky stressAddRemoveNode test (`#2206 <https://github.com/ros2/rclcpp/issues/2206>`_)
* Use TRACETOOLS\_ prefix for tracepoint-related macros (`#2162 <https://github.com/ros2/rclcpp/issues/2162>`_)
* Contributors: Chris Lalancette, Christophe Bedard, Michael Carroll
21.2.0 (2023-06-07)
-------------------
* remove nolint since ament_cpplint updated for the c++17 header (`#2198 <https://github.com/ros2/rclcpp/issues/2198>`_)
* 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
21.1.1 (2023-05-11)
-------------------
* 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
21.1.0 (2023-04-27)
-------------------
* 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

@@ -10,11 +10,14 @@ find_package(builtin_interfaces REQUIRED)
find_package(libstatistics_collector REQUIRED)
find_package(rcl REQUIRED)
find_package(rcl_interfaces REQUIRED)
find_package(rcl_logging_interface REQUIRED)
find_package(rcl_yaml_param_parser REQUIRED)
find_package(rcpputils REQUIRED)
find_package(rcutils REQUIRED)
find_package(rmw REQUIRED)
find_package(rosgraph_msgs REQUIRED)
find_package(rosidl_dynamic_typesupport REQUIRED)
find_package(rosidl_runtime_c REQUIRED)
find_package(rosidl_runtime_cpp REQUIRED)
find_package(rosidl_typesupport_c REQUIRED)
find_package(rosidl_typesupport_cpp REQUIRED)
@@ -106,6 +109,7 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/qos.cpp
src/rclcpp/event_handler.cpp
src/rclcpp/qos_overriding_options.cpp
src/rclcpp/rate.cpp
src/rclcpp/serialization.cpp
src/rclcpp/serialized_message.cpp
src/rclcpp/service.cpp
@@ -200,22 +204,28 @@ target_include_directories(${PROJECT_NAME} PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>")
target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT})
# specific order: dependents before dependencies
ament_target_dependencies(${PROJECT_NAME}
"ament_index_cpp"
"libstatistics_collector"
"rcl"
"rcl_interfaces"
"rcl_yaml_param_parser"
"rcpputils"
"rcutils"
"builtin_interfaces"
"rosgraph_msgs"
"rosidl_typesupport_cpp"
"rosidl_runtime_cpp"
"statistics_msgs"
"tracetools"
target_link_libraries(${PROJECT_NAME} PUBLIC
${builtin_interfaces_TARGETS}
libstatistics_collector::libstatistics_collector
rcl::rcl
${rcl_interfaces_TARGETS}
rcl_yaml_param_parser::rcl_yaml_param_parser
rcpputils::rcpputils
rcutils::rcutils
rmw::rmw
${rosgraph_msgs_TARGETS}
rosidl_dynamic_typesupport::rosidl_dynamic_typesupport
rosidl_runtime_c::rosidl_runtime_c
rosidl_runtime_cpp::rosidl_runtime_cpp
rosidl_typesupport_cpp::rosidl_typesupport_cpp
${statistics_msgs_TARGETS}
tracetools::tracetools
${CMAKE_THREAD_LIBS_INIT}
)
target_link_libraries(${PROJECT_NAME} PRIVATE
ament_index_cpp::ament_index_cpp
rcl_logging_interface::rcl_logging_interface
)
# Causes the visibility macros to use dllexport rather than dllimport,
@@ -237,20 +247,23 @@ ament_export_libraries(${PROJECT_NAME})
# Export modern CMake targets
ament_export_targets(${PROJECT_NAME})
# specific order: dependents before dependencies
ament_export_dependencies(ament_index_cpp)
ament_export_dependencies(libstatistics_collector)
ament_export_dependencies(rcl)
ament_export_dependencies(rcpputils)
ament_export_dependencies(rcutils)
ament_export_dependencies(builtin_interfaces)
ament_export_dependencies(rosgraph_msgs)
ament_export_dependencies(rosidl_typesupport_cpp)
ament_export_dependencies(rosidl_typesupport_c)
ament_export_dependencies(rosidl_runtime_cpp)
ament_export_dependencies(rcl_yaml_param_parser)
ament_export_dependencies(statistics_msgs)
ament_export_dependencies(tracetools)
ament_export_dependencies(
builtin_interfaces
libstatistics_collector
rcl
rcl_interfaces
rcl_yaml_param_parser
rcpputils
rcutils
rmw
rosgraph_msgs
rosidl_dynamic_typesupport
rosidl_runtime_c
rosidl_runtime_cpp
rosidl_typesupport_cpp
statistics_msgs
tracetools
)
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)

View File

@@ -2,7 +2,7 @@
The ROS client library in C++.
Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) for a complete list of its main components and features.
The link to the latest rclcpp API documentation, which includes a complete list of its main components and features, can be found on the rclcpp package info page, at the [ROS Index](https://index.ros.org/p/rclcpp/).
## Quality Declaration

View File

@@ -156,7 +156,7 @@ public:
const std::shared_ptr<rmw_request_id_t> & request_header,
std::shared_ptr<typename ServiceT::Request> request)
{
TRACEPOINT(callback_start, static_cast<const void *>(this), false);
TRACETOOLS_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);
}
TRACEPOINT(callback_end, static_cast<const void *>(this));
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
return response;
}
@@ -191,9 +191,9 @@ public:
#ifndef TRACETOOLS_DISABLED
std::visit(
[this](auto && arg) {
if (TRACEPOINT_ENABLED(rclcpp_callback_register)) {
if (TRACETOOLS_TRACEPOINT_ENABLED(rclcpp_callback_register)) {
char * symbol = tracetools::get_symbol(arg);
DO_TRACEPOINT(
TRACETOOLS_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> // NOLINT[build/include_order]
#include <variant>
#include "rosidl_runtime_cpp/traits.hpp"
#include "tracetools/tracetools.h"
@@ -30,19 +30,20 @@
#include "rclcpp/detail/subscription_callback_type_helper.hpp"
#include "rclcpp/function_traits.hpp"
#include "rclcpp/message_info.hpp"
#include "rclcpp/serialization.hpp"
#include "rclcpp/serialized_message.hpp"
#include "rclcpp/type_adapter.hpp"
template<class>
inline constexpr bool always_false_v = false;
namespace rclcpp
{
namespace detail
{
template<class>
inline constexpr bool always_false_v = false;
template<typename MessageT, typename AllocatorT>
struct MessageDeleterHelper
{
@@ -158,13 +159,14 @@ struct AnySubscriptionCallbackPossibleTypes
template<
typename MessageT,
typename AllocatorT,
bool is_adapted_type = rclcpp::TypeAdapter<MessageT>::is_specialized::value
bool is_adapted_type = rclcpp::TypeAdapter<MessageT>::is_specialized::value,
bool is_serialized_type = serialization_traits::is_serialized_message_class<MessageT>::value
>
struct AnySubscriptionCallbackHelper;
/// Specialization for when MessageT is not a TypeAdapter.
template<typename MessageT, typename AllocatorT>
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, false>
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, false, false>
{
using CallbackTypes = AnySubscriptionCallbackPossibleTypes<MessageT, AllocatorT>;
@@ -194,7 +196,7 @@ struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, false>
/// Specialization for when MessageT is a TypeAdapter.
template<typename MessageT, typename AllocatorT>
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, true>
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, true, false>
{
using CallbackTypes = AnySubscriptionCallbackPossibleTypes<MessageT, AllocatorT>;
@@ -232,6 +234,26 @@ struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, true>
>;
};
/// Specialization for when MessageT is a SerializedMessage to exclude duplicated declarations.
template<typename MessageT, typename AllocatorT>
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, false, true>
{
using CallbackTypes = AnySubscriptionCallbackPossibleTypes<MessageT, AllocatorT>;
using variant_type = std::variant<
typename CallbackTypes::ConstRefSerializedMessageCallback,
typename CallbackTypes::ConstRefSerializedMessageWithInfoCallback,
typename CallbackTypes::UniquePtrSerializedMessageCallback,
typename CallbackTypes::UniquePtrSerializedMessageWithInfoCallback,
typename CallbackTypes::SharedConstPtrSerializedMessageCallback,
typename CallbackTypes::SharedConstPtrSerializedMessageWithInfoCallback,
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageCallback,
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageWithInfoCallback,
typename CallbackTypes::SharedPtrSerializedMessageCallback,
typename CallbackTypes::SharedPtrSerializedMessageWithInfoCallback
>;
};
} // namespace detail
template<
@@ -487,12 +509,14 @@ public:
}
// Dispatch when input is a ros message and the output could be anything.
void
template<typename TMsg = ROSMessageType>
typename std::enable_if<!serialization_traits::is_serialized_message_class<TMsg>::value,
void>::type
dispatch(
std::shared_ptr<ROSMessageType> message,
const rclcpp::MessageInfo & message_info)
{
TRACEPOINT(callback_start, static_cast<const void *>(this), false);
TRACETOOLS_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) {
@@ -580,19 +604,19 @@ public:
}
// condition to catch unhandled callback types
else { // NOLINT[readability/braces]
static_assert(always_false_v<T>, "unhandled callback type");
static_assert(detail::always_false_v<T>, "unhandled callback type");
}
}, callback_variant_);
TRACEPOINT(callback_end, static_cast<const void *>(this));
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
}
// Dispatch when input is a serialized message and the output could be anything.
void
dispatch(
std::shared_ptr<rclcpp::SerializedMessage> serialized_message,
std::shared_ptr<const rclcpp::SerializedMessage> serialized_message,
const rclcpp::MessageInfo & message_info)
{
TRACEPOINT(callback_start, static_cast<const void *>(this), false);
TRACETOOLS_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) {
@@ -660,10 +684,10 @@ public:
}
// condition to catch unhandled callback types
else { // NOLINT[readability/braces]
static_assert(always_false_v<T>, "unhandled callback type");
static_assert(detail::always_false_v<T>, "unhandled callback type");
}
}, callback_variant_);
TRACEPOINT(callback_end, static_cast<const void *>(this));
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
}
void
@@ -671,7 +695,7 @@ public:
std::shared_ptr<const SubscribedType> message,
const rclcpp::MessageInfo & message_info)
{
TRACEPOINT(callback_start, static_cast<const void *>(this), true);
TRACETOOLS_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) {
@@ -790,10 +814,10 @@ public:
}
// condition to catch unhandled callback types
else { // NOLINT[readability/braces]
static_assert(always_false_v<T>, "unhandled callback type");
static_assert(detail::always_false_v<T>, "unhandled callback type");
}
}, callback_variant_);
TRACEPOINT(callback_end, static_cast<const void *>(this));
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
}
void
@@ -801,7 +825,7 @@ public:
std::unique_ptr<SubscribedType, SubscribedTypeDeleter> message,
const rclcpp::MessageInfo & message_info)
{
TRACEPOINT(callback_start, static_cast<const void *>(this), true);
TRACETOOLS_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) {
@@ -924,10 +948,10 @@ public:
}
// condition to catch unhandled callback types
else { // NOLINT[readability/braces]
static_assert(always_false_v<T>, "unhandled callback type");
static_assert(detail::always_false_v<T>, "unhandled callback type");
}
}, callback_variant_);
TRACEPOINT(callback_end, static_cast<const void *>(this));
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
}
constexpr
@@ -965,9 +989,9 @@ public:
#ifndef TRACETOOLS_DISABLED
std::visit(
[this](auto && callback) {
if (TRACEPOINT_ENABLED(rclcpp_callback_register)) {
if (TRACETOOLS_TRACEPOINT_ENABLED(rclcpp_callback_register)) {
char * symbol = tracetools::get_symbol(callback);
DO_TRACEPOINT(
TRACETOOLS_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> // NOLINT, cpplint doesn't think this is a cpp std header
#include <optional>
#include <sstream>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <variant> // NOLINT
#include <variant>
#include <vector>
#include "rcl/client.h"
@@ -363,12 +363,16 @@ 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>
@@ -845,7 +849,7 @@ protected:
"Received invalid sequence number. Ignoring...");
return std::nullopt;
}
std::optional<CallbackInfoVariant> value = std::move(it->second.second);
auto value = std::move(it->second.second);
this->pending_requests_.erase(request_number);
return value;
}

View File

@@ -0,0 +1,82 @@
// Copyright 2023 Open Navigation LLC
//
// 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__COPY_ALL_PARAMETER_VALUES_HPP_
#define RCLCPP__COPY_ALL_PARAMETER_VALUES_HPP_
#include <string>
#include <vector>
#include "rcl_interfaces/srv/list_parameters.hpp"
#include "rcl_interfaces/msg/parameter_descriptor.hpp"
#include "rcl_interfaces/msg/set_parameters_result.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/logger.hpp"
#include "rclcpp/logging.hpp"
namespace rclcpp
{
/**
* Copy all parameters from one source node to another destination node.
* May throw exceptions if parameters from source are uninitialized or undeclared.
* \param source Node to copy parameters from
* \param destination Node to copy parameters to
* \param override_existing_params Default false. Whether to override existing destination params
* if both the source and destination contain the same parameter.
*/
template<typename NodeT1, typename NodeT2>
void
copy_all_parameter_values(
const NodeT1 & source, const NodeT2 & destination, const bool override_existing_params = false)
{
using Parameters = std::vector<rclcpp::Parameter>;
using Descriptions = std::vector<rcl_interfaces::msg::ParameterDescriptor>;
auto source_params = source->get_node_parameters_interface();
auto dest_params = destination->get_node_parameters_interface();
rclcpp::Logger logger = destination->get_node_logging_interface()->get_logger();
std::vector<std::string> param_names = source_params->list_parameters({}, 0).names;
Parameters params = source_params->get_parameters(param_names);
Descriptions descriptions = source_params->describe_parameters(param_names);
for (unsigned int idx = 0; idx != params.size(); idx++) {
if (!dest_params->has_parameter(params[idx].get_name())) {
dest_params->declare_parameter(
params[idx].get_name(), params[idx].get_parameter_value(), descriptions[idx]);
} else if (override_existing_params) {
try {
rcl_interfaces::msg::SetParametersResult result =
dest_params->set_parameters_atomically({params[idx]});
if (!result.successful) {
// Parameter update rejected or read-only
RCLCPP_WARN(
logger,
"Unable to set parameter (%s): %s!",
params[idx].get_name().c_str(), result.reason.c_str());
}
} catch (const rclcpp::exceptions::InvalidParameterTypeException & e) {
RCLCPP_WARN(
logger,
"Unable to set parameter (%s): incompatable parameter type (%s)!",
params[idx].get_name().c_str(), e.what());
}
}
}
}
} // namespace rclcpp
#endif // RCLCPP__COPY_ALL_PARAMETER_VALUES_HPP_

View File

@@ -45,13 +45,15 @@ namespace rclcpp
* Not all publisher options are currently respected, the only relevant options for this
* publisher are `event_callbacks`, `use_default_callbacks`, and `%callback_group`.
*/
template<typename AllocatorT = std::allocator<void>>
template<
typename CallbackT,
typename AllocatorT = std::allocator<void>>
std::shared_ptr<GenericSubscription> create_generic_subscription(
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr topics_interface,
const std::string & topic_name,
const std::string & topic_type,
const rclcpp::QoS & qos,
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback,
CallbackT && callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
)
@@ -60,13 +62,20 @@ std::shared_ptr<GenericSubscription> create_generic_subscription(
auto ts_lib = rclcpp::get_typesupport_library(
topic_type, "rosidl_typesupport_cpp");
auto allocator = options.get_allocator();
using rclcpp::AnySubscriptionCallback;
AnySubscriptionCallback<rclcpp::SerializedMessage, AllocatorT>
any_subscription_callback(*allocator);
any_subscription_callback.set(std::forward<CallbackT>(callback));
auto subscription = std::make_shared<GenericSubscription>(
topics_interface->get_node_base_interface(),
std::move(ts_lib),
topic_name,
topic_type,
qos,
callback,
any_subscription_callback,
options);
topics_interface->add_subscription(subscription, options.callback_group);

View File

@@ -50,8 +50,8 @@ template<
typename SubscriptionT,
typename MessageMemoryStrategyT,
typename NodeParametersT,
typename NodeTopicsT,
typename ROSMessageType = typename SubscriptionT::ROSMessageType>
typename NodeTopicsT
>
typename std::shared_ptr<SubscriptionT>
create_subscription(
NodeParametersT & node_parameters,
@@ -70,7 +70,7 @@ create_subscription(
using rclcpp::node_interfaces::get_node_topics_interface;
auto node_topics_interface = get_node_topics_interface(node_topics);
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>>
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics>
subscription_topic_stats = nullptr;
if (rclcpp::detail::resolve_enable_topic_statistics(
@@ -80,8 +80,7 @@ create_subscription(
if (options.topic_stats_options.publish_period <= std::chrono::milliseconds(0)) {
throw std::invalid_argument(
"topic_stats_options.publish_period must be greater than 0, specified value of " +
std::to_string(options.topic_stats_options.publish_period.count()) +
" ms");
std::to_string(options.topic_stats_options.publish_period.count()) + " ms");
}
std::shared_ptr<Publisher<statistics_msgs::msg::MetricsMessage>>
@@ -89,14 +88,14 @@ create_subscription(
node_parameters,
node_topics_interface,
options.topic_stats_options.publish_topic,
qos);
options.topic_stats_options.qos);
subscription_topic_stats = std::make_shared<
rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>
>(node_topics_interface->get_node_base_interface()->get_name(), publisher);
subscription_topic_stats =
std::make_shared<rclcpp::topic_statistics::SubscriptionTopicStatistics>(
node_topics_interface->get_node_base_interface()->get_name(), publisher);
std::weak_ptr<
rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>
rclcpp::topic_statistics::SubscriptionTopicStatistics
> weak_subscription_topic_stats(subscription_topic_stats);
auto sub_call_back = [weak_subscription_topic_stats]() {
auto subscription_topic_stats = weak_subscription_topic_stats.lock();

View File

@@ -90,7 +90,8 @@ create_timer(
rclcpp::Clock::SharedPtr clock,
rclcpp::Duration period,
CallbackT && callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
rclcpp::CallbackGroup::SharedPtr group = nullptr,
bool autostart = true)
{
return create_timer(
clock,
@@ -98,7 +99,8 @@ create_timer(
std::forward<CallbackT>(callback),
group,
node_base.get(),
node_timers.get());
node_timers.get(),
autostart);
}
/// Create a timer with a given clock
@@ -109,7 +111,8 @@ create_timer(
rclcpp::Clock::SharedPtr clock,
rclcpp::Duration period,
CallbackT && callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
rclcpp::CallbackGroup::SharedPtr group = nullptr,
bool autostart = true)
{
return create_timer(
clock,
@@ -117,7 +120,8 @@ create_timer(
std::forward<CallbackT>(callback),
group,
rclcpp::node_interfaces::get_node_base_interface(node).get(),
rclcpp::node_interfaces::get_node_timers_interface(node).get());
rclcpp::node_interfaces::get_node_timers_interface(node).get(),
autostart);
}
/// Convenience method to create a general timer with node resources.
@@ -132,6 +136,7 @@ create_timer(
* \param group callback group
* \param node_base node base interface
* \param node_timers node timer interface
* \param autostart defines if the timer should start it's countdown on initialization or not.
* \return shared pointer to a generic timer
* \throws std::invalid_argument if either clock, node_base or node_timers
* are nullptr, or period is negative or too large
@@ -144,7 +149,8 @@ create_timer(
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group,
node_interfaces::NodeBaseInterface * node_base,
node_interfaces::NodeTimersInterface * node_timers)
node_interfaces::NodeTimersInterface * node_timers,
bool autostart = true)
{
if (clock == nullptr) {
throw std::invalid_argument{"clock cannot be null"};
@@ -160,7 +166,7 @@ create_timer(
// Add a new generic timer.
auto timer = rclcpp::GenericTimer<CallbackT>::make_shared(
std::move(clock), period_ns, std::move(callback), node_base->get_context());
std::move(clock), period_ns, std::move(callback), node_base->get_context(), autostart);
node_timers->add_timer(timer, group);
return timer;
}
@@ -187,7 +193,8 @@ create_wall_timer(
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group,
node_interfaces::NodeBaseInterface * node_base,
node_interfaces::NodeTimersInterface * node_timers)
node_interfaces::NodeTimersInterface * node_timers,
bool autostart = true)
{
if (node_base == nullptr) {
throw std::invalid_argument{"input node_base cannot be null"};
@@ -201,7 +208,7 @@ create_wall_timer(
// Add a new wall timer.
auto timer = rclcpp::WallTimer<CallbackT>::make_shared(
period_ns, std::move(callback), node_base->get_context());
period_ns, std::move(callback), node_base->get_context(), autostart);
node_timers->add_timer(timer, group);
return timer;
}

View File

@@ -206,6 +206,14 @@ public:
const std::vector<std::string> unknown_ros_args;
};
/// Thrown when an unknown type is passed
class UnknownTypeError : public std::runtime_error
{
public:
explicit UnknownTypeError(const std::string & type)
: std::runtime_error("Unknown type: " + type) {}
};
/// Thrown when an invalid rclcpp::Event object or SharedPtr is encountered.
class InvalidEventError : public std::runtime_error
{
@@ -222,6 +230,14 @@ public:
: std::runtime_error("event already registered") {}
};
/// Thrown when a callback group is missing from the node, when it wants to utilize the group.
class MissingGroupNodeException : public std::runtime_error
{
public:
explicit MissingGroupNodeException(const std::string & obj_type)
: std::runtime_error("cannot create: " + obj_type + " , callback group not in node") {}
};
/// Thrown if passed parameters are inconsistent or invalid
class InvalidParametersException : public std::runtime_error
{

View File

@@ -297,6 +297,21 @@ public:
virtual void
spin_some(std::chrono::nanoseconds max_duration = std::chrono::nanoseconds(0));
/// Add a node, complete all immediately available work exhaustively, and remove the node.
/**
* \param[in] node Shared pointer to the node to add.
*/
RCLCPP_PUBLIC
void
spin_node_all(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
std::chrono::nanoseconds max_duration);
/// Convenience function which takes Node and forwards NodeBaseInterface.
RCLCPP_PUBLIC
void
spin_node_all(std::shared_ptr<rclcpp::Node> node, std::chrono::nanoseconds max_duration);
/// Collect and execute work repeatedly within a duration or until no more work is available.
/**
* This function can be overridden. The default implementation is suitable for a

View File

@@ -29,6 +29,18 @@
namespace rclcpp
{
/// Create a default single-threaded executor and execute all available work exhaustively.
/** \param[in] node_ptr Shared pointer to the node to spin. */
RCLCPP_PUBLIC
void
spin_all(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
std::chrono::nanoseconds max_duration);
RCLCPP_PUBLIC
void
spin_all(rclcpp::Node::SharedPtr node_ptr, std::chrono::nanoseconds max_duration);
/// Create a default single-threaded executor and execute any immediately available work.
/** \param[in] node_ptr Shared pointer to the node to spin. */
RCLCPP_PUBLIC
@@ -108,9 +120,7 @@ spin_until_future_complete(
const FutureT & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
rclcpp::ExecutorOptions options;
options.context = node_ptr->get_context();
rclcpp::executors::SingleThreadedExecutor executor(options);
rclcpp::executors::SingleThreadedExecutor executor;
return executors::spin_node_until_future_complete<FutureT>(executor, node_ptr, future, timeout);
}

View File

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

View File

@@ -44,6 +44,7 @@ public:
virtual bool has_data() const = 0;
virtual bool use_take_shared_method() const = 0;
virtual size_t available_capacity() const = 0;
};
template<
@@ -95,7 +96,7 @@ public:
buffer_ = std::move(buffer_impl);
TRACEPOINT(
TRACETOOLS_TRACEPOINT(
rclcpp_buffer_to_ipb,
static_cast<const void *>(buffer_.get()),
static_cast<const void *>(this));
@@ -143,6 +144,11 @@ 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,7 +52,10 @@ public:
if (capacity == 0) {
throw std::invalid_argument("capacity must be a positive, non-zero value");
}
TRACEPOINT(rclcpp_construct_ring_buffer, static_cast<const void *>(this), capacity_);
TRACETOOLS_TRACEPOINT(
rclcpp_construct_ring_buffer,
static_cast<const void *>(this),
capacity_);
}
virtual ~RingBufferImplementation() {}
@@ -69,7 +72,7 @@ public:
write_index_ = next_(write_index_);
ring_buffer_[write_index_] = std::move(request);
TRACEPOINT(
TRACETOOLS_TRACEPOINT(
rclcpp_ring_buffer_enqueue,
static_cast<const void *>(this),
write_index_,
@@ -98,7 +101,7 @@ public:
}
auto request = std::move(ring_buffer_[read_index_]);
TRACEPOINT(
TRACETOOLS_TRACEPOINT(
rclcpp_ring_buffer_dequeue,
static_cast<const void *>(this),
read_index_,
@@ -148,9 +151,21 @@ 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()
{
TRACEPOINT(rclcpp_ring_buffer_clear, static_cast<const void *>(this));
TRACETOOLS_TRACEPOINT(rclcpp_ring_buffer_clear, static_cast<const void *>(this));
}
private:
@@ -189,6 +204,17 @@ 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,9 +274,12 @@ private:
rclcpp::experimental::executors::EventsQueue::UniquePtr events_queue_;
std::shared_ptr<rclcpp::executors::ExecutorEntitiesCollector> entities_collector_;
std::shared_ptr<rclcpp::executors::ExecutorEntitiesCollection> current_entities_collection_;
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_;
/// Flag used to reduce the number of unnecessary waitable events
std::atomic<bool> notify_waitable_event_pushed_ {false};

View File

@@ -306,6 +306,11 @@ 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
{
@@ -462,7 +467,7 @@ private:
auto ptr = MessageAllocTraits::allocate(allocator, 1);
MessageAllocTraits::construct(allocator, ptr, *message);
subscription->provide_intra_process_data(std::move(MessageUniquePtr(ptr, deleter)));
subscription->provide_intra_process_data(MessageUniquePtr(ptr, deleter));
}
continue;
@@ -505,7 +510,7 @@ private:
MessageAllocTraits::construct(allocator, ptr, *message);
ros_message_subscription->provide_intra_process_message(
std::move(MessageUniquePtr(ptr, deleter)));
MessageUniquePtr(ptr, deleter));
}
}
}

View File

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

View File

@@ -62,6 +62,11 @@ 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_));
TRACEPOINT(
TRACETOOLS_TRACEPOINT(
rclcpp_ipb_to_subscription,
static_cast<const void *>(buffer_.get()),
static_cast<const void *>(this));
@@ -169,6 +169,11 @@ 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

@@ -527,7 +527,7 @@ private:
void execute_ready_timers_unsafe();
// Callback to be called when timer is ready
std::function<void(const rclcpp::TimerBase *)> on_ready_callback_ = nullptr;
std::function<void(const rclcpp::TimerBase *)> on_ready_callback_;
// Thread used to run the timers execution task
std::thread timers_thread_;

View File

@@ -77,7 +77,7 @@ public:
: rclcpp::PublisherBase(
node_base,
topic_name,
*rclcpp::get_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
*rclcpp::get_message_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
options.template to_rcl_publisher_options<rclcpp::SerializedMessage>(qos),
// NOTE(methylDragon): Passing these args separately is necessary for event binding
options.event_callbacks,

View File

@@ -74,18 +74,21 @@ public:
const std::string & topic_name,
const std::string & topic_type,
const rclcpp::QoS & qos,
// TODO(nnmm): Add variant for callback with message info. See issue #1604.
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback,
AnySubscriptionCallback<rclcpp::SerializedMessage, AllocatorT> callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options)
: SubscriptionBase(
node_base,
*rclcpp::get_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
*rclcpp::get_message_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
topic_name,
options.to_rcl_subscription_options(qos),
options.event_callbacks,
options.use_default_callbacks,
DeliveredMessageKind::SERIALIZED_MESSAGE),
callback_(callback),
callback_([callback](
std::shared_ptr<const rclcpp::SerializedMessage> serialized_message,
const rclcpp::MessageInfo & message_info) mutable {
callback.dispatch(serialized_message, message_info);
}),
ts_lib_(ts_lib)
{}
@@ -151,7 +154,9 @@ public:
private:
RCLCPP_DISABLE_COPY(GenericSubscription)
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback_;
std::function<void(
std::shared_ptr<const rclcpp::SerializedMessage>,
const rclcpp::MessageInfo)> callback_;
// The type support library should stay loaded, so it is stored in the GenericSubscription
std::shared_ptr<rcpputils::SharedLibrary> ts_lib_;
};

View File

@@ -126,9 +126,6 @@ private:
std::shared_ptr<std::pair<std::string, std::string>> logger_sublogger_pairname_ = nullptr;
public:
RCLCPP_PUBLIC
Logger(const Logger &) = default;
/// Get the name of this logger.
/**
* \return the full name of the logger including any prefixes, or

View File

@@ -233,13 +233,15 @@ public:
* \param[in] period Time interval between triggers of the callback.
* \param[in] callback User-defined callback function.
* \param[in] group Callback group to execute this timer's callback in.
* \param[in] autostart The state of the clock on initialization.
*/
template<typename DurationRepT = int64_t, typename DurationT = std::milli, typename CallbackT>
typename rclcpp::WallTimer<CallbackT>::SharedPtr
create_wall_timer(
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
rclcpp::CallbackGroup::SharedPtr group = nullptr,
bool autostart = true);
/// Create a timer that uses the node clock to drive the callback.
/**
@@ -356,12 +358,14 @@ public:
* `%callback_group`.
* \return Shared pointer to the created generic subscription.
*/
template<typename AllocatorT = std::allocator<void>>
template<
typename CallbackT,
typename AllocatorT = std::allocator<void>>
std::shared_ptr<rclcpp::GenericSubscription> create_generic_subscription(
const std::string & topic_name,
const std::string & topic_type,
const rclcpp::QoS & qos,
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback,
CallbackT && callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
)
@@ -970,7 +974,16 @@ public:
/// Return a list of parameters with any of the given prefixes, up to the given depth.
/**
* \todo: properly document and test this method.
* Parameters are separated into a hierarchy using the "." (dot) character.
* The "prefixes" argument is a way to select only particular parts of the hierarchy.
*
* \param[in] prefixes The list of prefixes that should be searched for within the
* current parameters. If this vector of prefixes is empty, then list_parameters
* will return all parameters.
* \param[in] depth An unsigned integer that represents the recursive depth to search.
* If this depth = 0, then all parameters that fit the prefixes will be returned.
* \returns A ListParametersResult message which contains both an array of unique prefixes
* and an array of names that were matched to the prefixes given.
*/
RCLCPP_PUBLIC
rcl_interfaces::msg::ListParametersResult
@@ -1303,6 +1316,26 @@ public:
size_t
count_subscribers(const std::string & topic_name) const;
/// Return the number of clients created for a given service.
/**
* \param[in] service_name the actual service name used; it will not be automatically remapped.
* \return number of clients that have been created for the given service.
* \throws std::runtime_error if clients could not be counted
*/
RCLCPP_PUBLIC
size_t
count_clients(const std::string & service_name) const;
/// Return the number of services created for a given service.
/**
* \param[in] service_name the actual service name used; it will not be automatically remapped.
* \return number of services that have been created for the given service.
* \throws std::runtime_error if services could not be counted
*/
RCLCPP_PUBLIC
size_t
count_services(const std::string & service_name) const;
/// Return the topic endpoint information about publishers on a given topic.
/**
* The returned parameter is a list of topic endpoint information, where each item will contain
@@ -1592,16 +1625,18 @@ private:
rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock_;
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters_;
rclcpp::node_interfaces::NodeTimeSourceInterface::SharedPtr node_time_source_;
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr node_type_descriptions_;
rclcpp::node_interfaces::NodeWaitablesInterface::SharedPtr node_waitables_;
const rclcpp::NodeOptions node_options_;
const std::string sub_namespace_;
const std::string effective_namespace_;
/// 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_;
class NodeImpl;
// This member is meant to be a place to backport features into stable distributions,
// and new features targeting Rolling should not use this.
// See the comment in node.cpp for more information.
std::shared_ptr<NodeImpl> hidden_impl_{nullptr};
};
} // namespace rclcpp

View File

@@ -110,14 +110,16 @@ typename rclcpp::WallTimer<CallbackT>::SharedPtr
Node::create_wall_timer(
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group)
rclcpp::CallbackGroup::SharedPtr group,
bool autostart)
{
return rclcpp::create_wall_timer(
period,
std::move(callback),
group,
this->node_base_.get(),
this->node_timers_.get());
this->node_timers_.get(),
autostart);
}
template<typename DurationRepT, typename DurationT, typename CallbackT>
@@ -219,13 +221,13 @@ Node::create_generic_publisher(
);
}
template<typename AllocatorT>
template<typename CallbackT, typename AllocatorT>
std::shared_ptr<rclcpp::GenericSubscription>
Node::create_generic_subscription(
const std::string & topic_name,
const std::string & topic_type,
const rclcpp::QoS & qos,
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback,
CallbackT && callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options)
{
return rclcpp::create_generic_subscription(
@@ -233,7 +235,7 @@ Node::create_generic_subscription(
extend_name_with_sub_namespace(topic_name, this->get_sub_namespace()),
topic_type,
qos,
std::move(callback),
std::forward<CallbackT>(callback),
options
);
}

View File

@@ -113,6 +113,14 @@ public:
size_t
count_subscribers(const std::string & topic_name) const override;
RCLCPP_PUBLIC
size_t
count_clients(const std::string & service_name) const override;
RCLCPP_PUBLIC
size_t
count_services(const std::string & service_name) const override;
RCLCPP_PUBLIC
const rcl_guard_condition_t *
get_graph_guard_condition() const override;

View File

@@ -305,6 +305,24 @@ public:
size_t
count_subscribers(const std::string & topic_name) const = 0;
/// Return the number of clients created for a given service.
/*
* \param[in] service_name the actual service name used; it will not be automatically remapped.
*/
RCLCPP_PUBLIC
virtual
size_t
count_clients(const std::string & service_name) const = 0;
/// Return the number of services created for a given service.
/*
* \param[in] service_name the actual service name used; it will not be automatically remapped.
*/
RCLCPP_PUBLIC
virtual
size_t
count_services(const std::string & service_name) const = 0;
/// Return the rcl guard condition which is triggered when the ROS graph changes.
RCLCPP_PUBLIC
virtual

View File

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

View File

@@ -24,6 +24,7 @@
#include "rcl_interfaces/msg/parameter_type.hpp"
#include "rcl_interfaces/msg/parameter_value.hpp"
#include "rclcpp/exceptions/exceptions.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp

View File

@@ -390,7 +390,7 @@ public:
if (this->can_loan_messages()) {
// we release the ownership from the rclpp::LoanedMessage instance
// and let the middleware clean up the memory.
this->do_loaned_message_publish(std::move(loaned_msg.release()));
this->do_loaned_message_publish(loaned_msg.release());
} else {
// we don't release the ownership, let the middleware copy the ros message
// and thus the destructor of rclcpp::LoanedMessage cleans up the memory.
@@ -421,7 +421,7 @@ protected:
void
do_inter_process_publish(const ROSMessageType & msg)
{
TRACEPOINT(rclcpp_publish, nullptr, static_cast<const void *>(&msg));
TRACETOOLS_TRACEPOINT(rclcpp_publish, nullptr, static_cast<const void *>(&msg));
auto status = rcl_publish(publisher_handle_.get(), &msg, nullptr);
if (RCL_RET_PUBLISHER_INVALID == status) {
@@ -456,6 +456,7 @@ protected:
do_loaned_message_publish(
std::unique_ptr<ROSMessageType, std::function<void(ROSMessageType *)>> msg)
{
TRACETOOLS_TRACEPOINT(rclcpp_publish, nullptr, static_cast<const void *>(msg.get()));
auto status = rcl_publish_loaned_message(publisher_handle_.get(), msg.get(), nullptr);
if (RCL_RET_PUBLISHER_INVALID == status) {
@@ -484,7 +485,7 @@ protected:
if (!msg) {
throw std::runtime_error("cannot publish msg which is a null pointer");
}
TRACEPOINT(
TRACETOOLS_TRACEPOINT(
rclcpp_intra_publish,
static_cast<const void *>(publisher_handle_.get()),
msg.get());
@@ -506,7 +507,7 @@ protected:
if (!msg) {
throw std::runtime_error("cannot publish msg which is a null pointer");
}
TRACEPOINT(
TRACETOOLS_TRACEPOINT(
rclcpp_intra_publish,
static_cast<const void *>(publisher_handle_.get()),
msg.get());
@@ -529,7 +530,7 @@ protected:
if (!msg) {
throw std::runtime_error("cannot publish msg which is a null pointer");
}
TRACEPOINT(
TRACETOOLS_TRACEPOINT(
rclcpp_intra_publish,
static_cast<const void *>(publisher_handle_.get()),
msg.get());

View File

@@ -215,6 +215,17 @@ 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

@@ -19,6 +19,8 @@
#include <memory>
#include <thread>
#include "rclcpp/clock.hpp"
#include "rclcpp/duration.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -31,9 +33,20 @@ class RateBase
public:
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(RateBase)
RCLCPP_PUBLIC
virtual ~RateBase() {}
RCLCPP_PUBLIC
virtual bool sleep() = 0;
[[deprecated("use get_type() instead")]]
RCLCPP_PUBLIC
virtual bool is_steady() const = 0;
RCLCPP_PUBLIC
virtual rcl_clock_type_t get_type() const = 0;
RCLCPP_PUBLIC
virtual void reset() = 0;
};
@@ -42,14 +55,13 @@ using std::chrono::duration_cast;
using std::chrono::nanoseconds;
template<class Clock = std::chrono::high_resolution_clock>
class GenericRate : public RateBase
class [[deprecated("use rclcpp::Rate class instead of GenericRate")]] GenericRate : public RateBase
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(GenericRate)
explicit GenericRate(double rate)
: GenericRate<Clock>(
duration_cast<nanoseconds>(duration<double>(1.0 / rate)))
: period_(duration_cast<nanoseconds>(duration<double>(1.0 / rate))), last_interval_(Clock::now())
{}
explicit GenericRate(std::chrono::nanoseconds period)
: period_(period), last_interval_(Clock::now())
@@ -87,12 +99,18 @@ public:
return true;
}
[[deprecated("use get_type() instead")]]
virtual bool
is_steady() const
{
return Clock::is_steady;
}
virtual rcl_clock_type_t get_type() const
{
return Clock::is_steady ? RCL_STEADY_TIME : RCL_SYSTEM_TIME;
}
virtual void
reset()
{
@@ -112,8 +130,59 @@ private:
std::chrono::time_point<Clock, ClockDurationNano> last_interval_;
};
using Rate = GenericRate<std::chrono::system_clock>;
using WallRate = GenericRate<std::chrono::steady_clock>;
class Rate : public RateBase
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(Rate)
RCLCPP_PUBLIC
explicit Rate(
const double rate,
Clock::SharedPtr clock = std::make_shared<Clock>(RCL_SYSTEM_TIME));
RCLCPP_PUBLIC
explicit Rate(
const Duration & period,
Clock::SharedPtr clock = std::make_shared<Clock>(RCL_SYSTEM_TIME));
RCLCPP_PUBLIC
virtual bool
sleep();
[[deprecated("use get_type() instead")]]
RCLCPP_PUBLIC
virtual bool
is_steady() const;
RCLCPP_PUBLIC
virtual rcl_clock_type_t
get_type() const;
RCLCPP_PUBLIC
virtual void
reset();
RCLCPP_PUBLIC
std::chrono::nanoseconds
period() const;
private:
RCLCPP_DISABLE_COPY(Rate)
Clock::SharedPtr clock_;
Duration period_;
Time last_interval_;
};
class WallRate : public Rate
{
public:
RCLCPP_PUBLIC
explicit WallRate(const double rate);
RCLCPP_PUBLIC
explicit WallRate(const Duration & period);
};
} // namespace rclcpp

View File

@@ -54,6 +54,7 @@
* - rclcpp::ParameterValue
* - rclcpp::AsyncParametersClient
* - rclcpp::SyncParametersClient
* - rclcpp::copy_all_parameter_values()
* - rclcpp/parameter.hpp
* - rclcpp/parameter_value.hpp
* - rclcpp/parameter_client.hpp
@@ -95,6 +96,9 @@
* - Get the number of publishers or subscribers on a topic:
* - rclcpp::Node::count_publishers()
* - rclcpp::Node::count_subscribers()
* - Get the number of clients or servers on a service:
* - rclcpp::Node::count_clients()
* - rclcpp::Node::count_services()
*
* And components related to logging:
*
@@ -164,6 +168,7 @@
#include <csignal>
#include <memory>
#include "rclcpp/copy_all_parameter_values.hpp"
#include "rclcpp/executors.hpp"
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/logging.hpp"

View File

@@ -265,15 +265,19 @@ 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>
@@ -348,7 +352,7 @@ public:
rclcpp::exceptions::throw_from_rcl_error(ret, "could not create service");
}
TRACEPOINT(
TRACETOOLS_TRACEPOINT(
rclcpp_service_callback_added,
static_cast<const void *>(get_service_handle().get()),
static_cast<const void *>(&any_callback_));
@@ -383,7 +387,7 @@ public:
}
service_handle_ = service_handle;
TRACEPOINT(
TRACETOOLS_TRACEPOINT(
rclcpp_service_callback_added,
static_cast<const void *>(get_service_handle().get()),
static_cast<const void *>(&any_callback_));
@@ -420,7 +424,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;
TRACEPOINT(
TRACETOOLS_TRACEPOINT(
rclcpp_service_callback_added,
static_cast<const void *>(get_service_handle().get()),
static_cast<const void *>(&any_callback_));
@@ -495,7 +499,7 @@ public:
}
}
/// Configure service introspection.
/// Configure client introspection.
/**
* \param[in] clock clock to use to generate introspection timestamps
* \param[in] qos_service_event_pub QoS settings to use when creating the introspection publisher

View File

@@ -15,10 +15,17 @@
#ifndef RCLCPP__STRATEGIES__MESSAGE_POOL_MEMORY_STRATEGY_HPP_
#define RCLCPP__STRATEGIES__MESSAGE_POOL_MEMORY_STRATEGY_HPP_
#include <array>
#include <cstring>
#include <memory>
#include <mutex>
#include <stdexcept>
#include <type_traits>
#include "rosidl_runtime_cpp/traits.hpp"
#include "rclcpp/logger.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/message_memory_strategy.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -50,13 +57,24 @@ class MessagePoolMemoryStrategy
public:
RCLCPP_SMART_PTR_DEFINITIONS(MessagePoolMemoryStrategy)
/// Default constructor
MessagePoolMemoryStrategy()
: next_array_index_(0)
{
pool_mutex_ = std::make_shared<std::mutex>();
pool_ = std::shared_ptr<std::array<MessageT *, Size>>(
new std::array<MessageT *, Size>,
[](std::array<MessageT *, Size> * arr) {
for (size_t i = 0; i < Size; ++i) {
free((*arr)[i]);
}
delete arr;
});
free_list_ = std::make_shared<CircularArray<Size>>();
for (size_t i = 0; i < Size; ++i) {
pool_[i].msg_ptr_ = std::make_shared<MessageT>();
pool_[i].used = false;
(*pool_)[i] = static_cast<MessageT *>(malloc(sizeof(MessageT)));
free_list_->push_back(i);
}
}
@@ -68,43 +86,85 @@ public:
*/
std::shared_ptr<MessageT> borrow_message()
{
size_t current_index = next_array_index_;
next_array_index_ = (next_array_index_ + 1) % Size;
if (pool_[current_index].used) {
throw std::runtime_error("Tried to access message that was still in use! Abort.");
std::lock_guard<std::mutex> lock(*pool_mutex_);
if (free_list_->size() == 0) {
throw std::runtime_error("No more free slots in the pool");
}
pool_[current_index].msg_ptr_->~MessageT();
new (pool_[current_index].msg_ptr_.get())MessageT;
pool_[current_index].used = true;
return pool_[current_index].msg_ptr_;
size_t current_index = free_list_->pop_front();
return std::shared_ptr<MessageT>(
new((*pool_)[current_index]) MessageT(),
[pool = this->pool_, pool_mutex = this->pool_mutex_,
free_list = this->free_list_](MessageT * p) {
std::lock_guard<std::mutex> lock(*pool_mutex);
for (size_t i = 0; i < Size; ++i) {
if ((*pool)[i] == p) {
p->~MessageT();
free_list->push_back(i);
break;
}
}
});
}
/// Return a message to the message pool.
/**
* Manage metadata in the message pool ring buffer to release the message.
* This does nothing since the message isn't returned to the pool until the user has dropped
* all references.
* \param[in] msg Shared pointer to the message to return.
*/
void return_message(std::shared_ptr<MessageT> & msg)
{
for (size_t i = 0; i < Size; ++i) {
if (pool_[i].msg_ptr_ == msg) {
pool_[i].used = false;
return;
}
}
throw std::runtime_error("Unrecognized message ptr in return_message.");
(void)msg;
}
protected:
struct PoolMember
template<size_t N>
class CircularArray
{
std::shared_ptr<MessageT> msg_ptr_;
bool used;
public:
void push_back(const size_t v)
{
if (size_ + 1 > N) {
throw std::runtime_error("Tried to push too many items into the array");
}
array_[(front_ + size_) % N] = v;
++size_;
}
size_t pop_front()
{
if (size_ < 1) {
throw std::runtime_error("Tried to pop item from empty array");
}
size_t val = array_[front_];
front_ = (front_ + 1) % N;
--size_;
return val;
}
size_t size() const
{
return size_;
}
private:
size_t front_ = 0;
size_t size_ = 0;
std::array<size_t, N> array_;
};
std::array<PoolMember, Size> pool_;
size_t next_array_index_;
// It's very important that these are shared_ptrs, since users of this class might hold a
// reference to a pool item longer than the lifetime of the class. In that scenario, the
// shared_ptr ensures that the lifetime of these variables outlives this class, and hence ensures
// the custom destructor for each pool item can successfully run.
std::shared_ptr<std::mutex> pool_mutex_;
std::shared_ptr<std::array<MessageT *, Size>> pool_;
std::shared_ptr<CircularArray<Size>> free_list_;
};
} // namespace message_pool_memory_strategy

View File

@@ -104,7 +104,7 @@ public:
private:
using SubscriptionTopicStatisticsSharedPtr =
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>>;
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics>;
public:
RCLCPP_SMART_PTR_DEFINITIONS(Subscription)
@@ -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));
TRACEPOINT(
TRACETOOLS_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);
}
TRACEPOINT(
TRACETOOLS_TRACEPOINT(
rclcpp_subscription_init,
static_cast<const void *>(get_subscription_handle().get()),
static_cast<const void *>(this));
TRACEPOINT(
TRACETOOLS_TRACEPOINT(
rclcpp_subscription_callback_added,
static_cast<const void *>(this),
static_cast<const void *>(&any_callback_));
@@ -316,7 +316,7 @@ public:
if (subscription_topic_statistics_) {
const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
const auto time = rclcpp::Time(nanos.time_since_epoch().count());
subscription_topic_statistics_->handle_message(*typed_message, time);
subscription_topic_statistics_->handle_message(message_info.get_rmw_message_info(), time);
}
}
@@ -325,8 +325,20 @@ public:
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
const rclcpp::MessageInfo & message_info) override
{
// TODO(wjwwood): enable topic statistics for serialized messages
std::chrono::time_point<std::chrono::system_clock> now;
if (subscription_topic_statistics_) {
// get current time before executing callback to
// exclude callback duration from topic statistics result.
now = std::chrono::system_clock::now();
}
any_callback_.dispatch(serialized_message, message_info);
if (subscription_topic_statistics_) {
const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
const auto time = rclcpp::Time(nanos.time_since_epoch().count());
subscription_topic_statistics_->handle_message(message_info.get_rmw_message_info(), time);
}
}
void
@@ -357,7 +369,7 @@ public:
if (subscription_topic_statistics_) {
const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
const auto time = rclcpp::Time(nanos.time_since_epoch().count());
subscription_topic_statistics_->handle_message(*typed_message, time);
subscription_topic_statistics_->handle_message(message_info.get_rmw_message_info(), time);
}
}

View File

@@ -645,6 +645,14 @@ 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_;
@@ -669,9 +677,6 @@ 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

@@ -75,15 +75,14 @@ template<
typename CallbackT,
typename AllocatorT,
typename SubscriptionT = rclcpp::Subscription<MessageT, AllocatorT>,
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType,
typename ROSMessageType = typename SubscriptionT::ROSMessageType
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType
>
SubscriptionFactory
create_subscription_factory(
CallbackT && callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat,
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>>
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics>
subscription_topic_stats = nullptr
)
{

View File

@@ -77,6 +77,10 @@ struct SubscriptionOptionsBase
// Topic statistics publication period in ms. Defaults to one second.
// Only values greater than zero are allowed.
std::chrono::milliseconds publish_period{std::chrono::seconds(1)};
// An optional QoS which can provide topic_statistics with a stable QoS separate from
// the subscription's current QoS settings which could be unstable.
rclcpp::QoS qos = SystemDefaultsQoS();
};
TopicStatisticsOptions topic_stats_options;

View File

@@ -189,7 +189,7 @@ public:
*/
RCLCPP_PUBLIC
static Time
max();
max(rcl_clock_type_t clock_type = RCL_SYSTEM_TIME); // NOLINT
/// Get the seconds since epoch
/**

View File

@@ -53,12 +53,17 @@ public:
* \param clock A clock to use for time and sleeping
* \param period The interval at which the timer fires
* \param context node context
* \param autostart timer state on initialization
*
* In order to activate a timer that is not started on initialization,
* user should call the reset() method.
*/
RCLCPP_PUBLIC
explicit TimerBase(
Clock::SharedPtr clock,
std::chrono::nanoseconds period,
rclcpp::Context::SharedPtr context);
rclcpp::Context::SharedPtr context,
bool autostart = true);
/// TimerBase destructor
RCLCPP_PUBLIC
@@ -216,21 +221,22 @@ public:
* \param[in] period The interval at which the timer fires.
* \param[in] callback User-specified callback function.
* \param[in] context custom context to be used.
* \param autostart timer state on initialization
*/
explicit GenericTimer(
Clock::SharedPtr clock, std::chrono::nanoseconds period, FunctorT && callback,
rclcpp::Context::SharedPtr context
rclcpp::Context::SharedPtr context, bool autostart = true
)
: TimerBase(clock, period, context), callback_(std::forward<FunctorT>(callback))
: TimerBase(clock, period, context, autostart), callback_(std::forward<FunctorT>(callback))
{
TRACEPOINT(
TRACETOOLS_TRACEPOINT(
rclcpp_timer_callback_added,
static_cast<const void *>(get_timer_handle().get()),
reinterpret_cast<const void *>(&callback_));
#ifndef TRACETOOLS_DISABLED
if (TRACEPOINT_ENABLED(rclcpp_callback_register)) {
if (TRACETOOLS_TRACEPOINT_ENABLED(rclcpp_callback_register)) {
char * symbol = tracetools::get_symbol(callback_);
DO_TRACEPOINT(
TRACETOOLS_DO_TRACEPOINT(
rclcpp_callback_register,
reinterpret_cast<const void *>(&callback_),
symbol);
@@ -269,9 +275,9 @@ public:
void
execute_callback() override
{
TRACEPOINT(callback_start, reinterpret_cast<const void *>(&callback_), false);
TRACETOOLS_TRACEPOINT(callback_start, reinterpret_cast<const void *>(&callback_), false);
execute_callback_delegate<>();
TRACEPOINT(callback_end, reinterpret_cast<const void *>(&callback_));
TRACETOOLS_TRACEPOINT(callback_end, reinterpret_cast<const void *>(&callback_));
}
// void specialization
@@ -330,13 +336,15 @@ public:
* \param period The interval at which the timer fires
* \param callback The callback function to execute every interval
* \param context node context
* \param autostart timer state on initialization
*/
WallTimer(
std::chrono::nanoseconds period,
FunctorT && callback,
rclcpp::Context::SharedPtr context)
rclcpp::Context::SharedPtr context,
bool autostart = true)
: GenericTimer<FunctorT>(
std::make_shared<Clock>(RCL_STEADY_TIME), period, std::move(callback), context)
std::make_shared<Clock>(RCL_STEADY_TIME), period, std::move(callback), context, autostart)
{}
protected:

View File

@@ -48,21 +48,12 @@ using libstatistics_collector::moving_average_statistics::StatisticData;
/**
* Class used to collect, measure, and publish topic statistics data. Current statistics
* supported for subscribers are received message age and received message period.
*
* \tparam CallbackMessageT the subscribed message type
*/
template<typename CallbackMessageT>
*/
class SubscriptionTopicStatistics
{
using TopicStatsCollector =
libstatistics_collector::topic_statistics_collector::TopicStatisticsCollector<
CallbackMessageT>;
using ReceivedMessageAge =
libstatistics_collector::topic_statistics_collector::ReceivedMessageAgeCollector<
CallbackMessageT>;
using ReceivedMessagePeriod =
libstatistics_collector::topic_statistics_collector::ReceivedMessagePeriodCollector<
CallbackMessageT>;
using TopicStatsCollector = libstatistics_collector::TopicStatisticsCollector;
using ReceivedMessageAge = libstatistics_collector::ReceivedMessageAgeCollector;
using ReceivedMessagePeriod = libstatistics_collector::ReceivedMessagePeriodCollector;
public:
/// Construct a SubscriptionTopicStatistics object.
@@ -101,16 +92,16 @@ public:
/**
* This method acquires a lock to prevent race conditions to collectors list.
*
* \param received_message the message received by the subscription
* \param message_info the message info corresponding to the received message
* \param now_nanoseconds current time in nanoseconds
*/
virtual void handle_message(
const CallbackMessageT & received_message,
const rmw_message_info_t & message_info,
const rclcpp::Time now_nanoseconds) const
{
std::lock_guard<std::mutex> lock(mutex_);
for (const auto & collector : subscriber_statistics_collectors_) {
collector->OnMessageReceived(received_message, now_nanoseconds.nanoseconds());
collector->OnMessageReceived(message_info, now_nanoseconds.nanoseconds());
}
}

View File

@@ -22,6 +22,7 @@
#include "rcpputils/shared_library.hpp"
#include "rosidl_runtime_cpp/message_type_support_decl.hpp"
#include "rosidl_runtime_cpp/service_type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -40,11 +41,15 @@ get_typesupport_library(const std::string & type, const std::string & typesuppor
/// Extract the type support handle from the library.
/**
* The library needs to match the topic type. The shared library must stay loaded for the lifetime of the result.
*
* \deprecated Use get_message_typesupport_handle() instead
*
* \param[in] type The topic type, e.g. "std_msgs/msg/String"
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
* \param[in] library The shared type support library
* \return A type support handle
*/
[[deprecated("Use `get_message_typesupport_handle` instead")]]
RCLCPP_PUBLIC
const rosidl_message_type_support_t *
get_typesupport_handle(
@@ -52,6 +57,40 @@ get_typesupport_handle(
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library);
/// Extract the message type support handle from the library.
/**
* The library needs to match the topic type. The shared library must stay loaded for the lifetime of the result.
*
* \param[in] type The topic type, e.g. "std_msgs/msg/String"
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
* \param[in] library The shared type support library
* \throws std::runtime_error if the symbol of type not found in the library.
* \return A message type support handle
*/
RCLCPP_PUBLIC
const rosidl_message_type_support_t *
get_message_typesupport_handle(
const std::string & type,
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library);
/// Extract the service type support handle from the library.
/**
* The library needs to match the topic type. The shared library must stay loaded for the lifetime of the result.
*
* \param[in] type The service type, e.g. "std_srvs/srv/Empty"
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
* \param[in] library The shared type support library
* \throws std::runtime_error if the symbol of type not found in the library.
* \return A service type support handle
*/
RCLCPP_PUBLIC
const rosidl_service_type_support_t *
get_service_typesupport_handle(
const std::string & type,
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library);
} // namespace rclcpp
#endif // RCLCPP__TYPESUPPORT_HELPERS_HPP_

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.0.8</version>
<version>25.0.0</version>
<description>The ROS client library in C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
@@ -22,6 +22,7 @@
<build_depend>builtin_interfaces</build_depend>
<build_depend>rcl_interfaces</build_depend>
<build_depend>rosgraph_msgs</build_depend>
<build_depend>rosidl_runtime_c</build_depend>
<build_depend>rosidl_runtime_cpp</build_depend>
<build_depend>rosidl_typesupport_c</build_depend>
<build_depend>rosidl_typesupport_cpp</build_depend>
@@ -29,12 +30,14 @@
<build_export_depend>builtin_interfaces</build_export_depend>
<build_export_depend>rcl_interfaces</build_export_depend>
<build_export_depend>rosgraph_msgs</build_export_depend>
<build_export_depend>rosidl_runtime_c</build_export_depend>
<build_export_depend>rosidl_runtime_cpp</build_export_depend>
<build_export_depend>rosidl_typesupport_c</build_export_depend>
<build_export_depend>rosidl_typesupport_cpp</build_export_depend>
<depend>libstatistics_collector</depend>
<depend>rcl</depend>
<depend>rcl_logging_interface</depend>
<depend>rcl_yaml_param_parser</depend>
<depend>rcpputils</depend>
<depend>rcutils</depend>

View File

@@ -125,7 +125,6 @@ bool
ClientBase::wait_for_service_nanoseconds(std::chrono::nanoseconds timeout)
{
auto start = std::chrono::steady_clock::now();
// make an event to reuse, rather than create a new one each time
auto node_ptr = node_graph_.lock();
if (!node_ptr) {
throw InvalidNodeError();
@@ -138,6 +137,7 @@ ClientBase::wait_for_service_nanoseconds(std::chrono::nanoseconds timeout)
// check was non-blocking, return immediately
return false;
}
// make an event to reuse, rather than create a new one each time
auto event = node_ptr->get_graph_event();
// update the time even on the first loop to account for time spent in the first call
// to this->server_is_ready()

View File

@@ -462,7 +462,7 @@ template<Context::ShutdownType shutdown_type>
std::vector<rclcpp::Context::ShutdownCallback>
Context::get_shutdown_callback() const
{
const auto get_callback_vector = [this](auto & mutex, auto & callback_set) {
const auto get_callback_vector = [](auto & mutex, auto & callback_set) {
const std::lock_guard<std::mutex> lock(mutex);
std::vector<rclcpp::Context::ShutdownCallback> callbacks;
for (auto & callback : callback_set) {

View File

@@ -431,6 +431,22 @@ void Executor::spin_some(std::chrono::nanoseconds max_duration)
return this->spin_some_impl(max_duration, false);
}
void
Executor::spin_node_all(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
std::chrono::nanoseconds max_duration)
{
this->add_node(node, false);
spin_all(max_duration);
this->remove_node(node, false);
}
void
Executor::spin_node_all(std::shared_ptr<rclcpp::Node> node, std::chrono::nanoseconds max_duration)
{
this->spin_node_all(node->get_node_base_interface(), max_duration);
}
void Executor::spin_all(std::chrono::nanoseconds max_duration)
{
if (max_duration < 0ns) {
@@ -525,13 +541,13 @@ Executor::execute_any_executable(AnyExecutable & any_exec)
return;
}
if (any_exec.timer) {
TRACEPOINT(
TRACETOOLS_TRACEPOINT(
rclcpp_executor_execute,
static_cast<const void *>(any_exec.timer->get_timer_handle().get()));
execute_timer(any_exec.timer);
}
if (any_exec.subscription) {
TRACEPOINT(
TRACETOOLS_TRACEPOINT(
rclcpp_executor_execute,
static_cast<const void *>(any_exec.subscription->get_subscription_handle().get()));
execute_subscription(any_exec.subscription);
@@ -731,7 +747,7 @@ Executor::execute_client(
void
Executor::wait_for_work(std::chrono::nanoseconds timeout)
{
TRACEPOINT(rclcpp_executor_wait_for_work, timeout.count());
TRACETOOLS_TRACEPOINT(rclcpp_executor_wait_for_work, timeout.count());
{
std::lock_guard<std::mutex> guard(mutex_);
@@ -887,7 +903,7 @@ Executor::get_next_ready_executable_from_map(
const rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap &
weak_groups_to_nodes)
{
TRACEPOINT(rclcpp_executor_get_next_ready);
TRACETOOLS_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

@@ -14,12 +14,25 @@
#include "rclcpp/executors.hpp"
void
rclcpp::spin_all(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
std::chrono::nanoseconds max_duration)
{
rclcpp::executors::SingleThreadedExecutor exec;
exec.spin_node_all(node_ptr, max_duration);
}
void
rclcpp::spin_all(rclcpp::Node::SharedPtr node_ptr, std::chrono::nanoseconds max_duration)
{
rclcpp::spin_all(node_ptr->get_node_base_interface(), max_duration);
}
void
rclcpp::spin_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr)
{
rclcpp::ExecutorOptions options;
options.context = node_ptr->get_context();
rclcpp::executors::SingleThreadedExecutor exec(options);
rclcpp::executors::SingleThreadedExecutor exec;
exec.spin_node_some(node_ptr);
}
@@ -32,9 +45,7 @@ rclcpp::spin_some(rclcpp::Node::SharedPtr node_ptr)
void
rclcpp::spin(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr)
{
rclcpp::ExecutorOptions options;
options.context = node_ptr->get_context();
rclcpp::executors::SingleThreadedExecutor exec(options);
rclcpp::executors::SingleThreadedExecutor exec;
exec.add_node(node_ptr);
exec.spin();
exec.remove_node(node_ptr);

View File

@@ -273,10 +273,13 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
switch (event.type) {
case ExecutorEventType::CLIENT_EVENT:
{
auto client = this->retrieve_entity(
static_cast<const rcl_client_t *>(event.entity_key),
current_entities_collection_->clients);
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);
}
if (client) {
for (size_t i = 0; i < event.num_events; i++) {
execute_client(client);
@@ -287,9 +290,13 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
}
case ExecutorEventType::SUBSCRIPTION_EVENT:
{
auto subscription = this->retrieve_entity(
static_cast<const rcl_subscription_t *>(event.entity_key),
current_entities_collection_->subscriptions);
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);
}
if (subscription) {
for (size_t i = 0; i < event.num_events; i++) {
execute_subscription(subscription);
@@ -299,10 +306,13 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
}
case ExecutorEventType::SERVICE_EVENT:
{
auto service = this->retrieve_entity(
static_cast<const rcl_service_t *>(event.entity_key),
current_entities_collection_->services);
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);
}
if (service) {
for (size_t i = 0; i < event.num_events; i++) {
execute_service(service);
@@ -319,9 +329,13 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
}
case ExecutorEventType::WAITABLE_EVENT:
{
auto waitable = this->retrieve_entity(
static_cast<const rclcpp::Waitable *>(event.entity_key),
current_entities_collection_->waitables);
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);
}
if (waitable) {
for (size_t i = 0; i < event.num_events; i++) {
auto data = waitable->take_data_by_entity_id(event.waitable_data);
@@ -386,6 +400,7 @@ 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;
@@ -400,6 +415,9 @@ 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);
@@ -409,6 +427,9 @@ 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

@@ -28,9 +28,9 @@ using rclcpp::experimental::TimersManager;
TimersManager::TimersManager(
std::shared_ptr<rclcpp::Context> context,
std::function<void(const rclcpp::TimerBase *)> on_ready_callback)
: on_ready_callback_(on_ready_callback),
context_(context)
{
context_ = context;
on_ready_callback_ = on_ready_callback;
}
TimersManager::~TimersManager()

View File

@@ -49,9 +49,9 @@ GenericSubscription::handle_message(
void
GenericSubscription::handle_serialized_message(
const std::shared_ptr<rclcpp::SerializedMessage> & message,
const rclcpp::MessageInfo &)
const rclcpp::MessageInfo & message_info)
{
callback_(message);
callback_(message, message_info);
}
void

View File

@@ -225,5 +225,52 @@ 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,6 +17,7 @@
#include <utility>
#include "rcl_logging_interface/rcl_logging_interface.h"
#include "rcl/error_handling.h"
#include "rcl/logging_rosout.h"
#include "rclcpp/exceptions.hpp"
@@ -80,10 +81,12 @@ Logger::get_child(const std::string & suffix)
{
std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
rcl_ret = rcl_logging_rosout_add_sublogger((*name_).c_str(), suffix.c_str());
if (RCL_RET_OK != rcl_ret) {
if (RCL_RET_NOT_FOUND == rcl_ret) {
rcl_reset_error();
} else if (RCL_RET_OK != rcl_ret) {
exceptions::throw_from_rcl_error(
rcl_ret, "failed to call rcl_logging_rosout_add_sublogger",
rcutils_get_error_state(), rcutils_reset_error);
rcl_get_error_state(), rcl_reset_error);
}
}
@@ -98,9 +101,7 @@ Logger::get_child(const std::string & suffix)
logger_sublogger_pairname_ptr->second.c_str());
delete logger_sublogger_pairname_ptr;
if (RCL_RET_OK != rcl_ret) {
exceptions::throw_from_rcl_error(
rcl_ret, "failed to call rcl_logging_rosout_remove_sublogger",
rcutils_get_error_state(), rcutils_reset_error);
rcl_reset_error();
}
});
}

View File

@@ -17,10 +17,7 @@
#include <limits>
#include <map>
#include <memory>
#include <mutex>
#include <shared_mutex>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
@@ -113,71 +110,21 @@ 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.
/// Internal implementation to provide hidden and API/ABI stable changes to the Node.
/**
* 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.
* This class is intended to be an "escape hatch" within a stable distribution, so that certain
* smaller features and bugfixes can be backported, having a place to put new members, while
* maintaining the ABI.
*
* This is not intended to be a parking place for new features, it should be used for backports
* only, left empty and unallocated in Rolling.
*/
class Node::BackportMembers
class Node::NodeImpl
{
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_;
NodeImpl() = default;
~NodeImpl() = default;
};
// Definition of static member declaration
Node::BackportMembers Node::backport_members_;
Node::Node(
const std::string & node_name,
@@ -276,13 +223,17 @@ Node::Node(
options.clock_qos(),
options.use_clock_thread()
)),
node_type_descriptions_(new rclcpp::node_interfaces::NodeTypeDescriptions(
node_base_,
node_logging_,
node_parameters_,
node_services_
)),
node_waitables_(new rclcpp::node_interfaces::NodeWaitables(node_base_.get())),
node_options_(options),
sub_namespace_(""),
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(
@@ -318,7 +269,8 @@ Node::Node(
node_waitables_(other.node_waitables_),
node_options_(other.node_options_),
sub_namespace_(extend_sub_namespace(other.get_sub_namespace(), sub_namespace)),
effective_namespace_(create_effective_namespace(other.get_namespace(), sub_namespace_))
effective_namespace_(create_effective_namespace(other.get_namespace(), sub_namespace_)),
hidden_impl_(other.hidden_impl_)
{
// Validate new effective namespace.
int validation_result;
@@ -344,7 +296,6 @@ 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();
@@ -571,6 +522,18 @@ Node::count_subscribers(const std::string & topic_name) const
return node_graph_->count_subscribers(topic_name);
}
size_t
Node::count_clients(const std::string & service_name) const
{
return node_graph_->count_clients(service_name);
}
size_t
Node::count_services(const std::string & service_name) const
{
return node_graph_->count_services(service_name);
}
std::vector<rclcpp::TopicEndpointInfo>
Node::get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle) const
{
@@ -667,7 +630,7 @@ Node::get_node_topics_interface()
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr
Node::get_node_type_descriptions_interface()
{
return backport_members_.get_node_type_descriptions_interface(this);
return node_type_descriptions_;
}
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr

View File

@@ -20,6 +20,9 @@
#include "rclcpp/node_interfaces/node_base.hpp"
#include "rcl/arguments.h"
#include "rcl/node_type_cache.h"
#include "rcl/logging.h"
#include "rcl/logging_rosout.h"
#include "rclcpp/exceptions.hpp"
#include "rcutils/logging_macros.h"
#include "rmw/validate_namespace.h"
@@ -54,17 +57,12 @@ NodeBase::NodeBase(
std::shared_ptr<std::recursive_mutex> logging_mutex = get_global_logging_mutex();
rcl_ret_t ret;
{
std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
// TODO(ivanpauno): /rosout Qos should be reconfigurable.
// TODO(ivanpauno): Instead of mutually excluding rcl_node_init with the global logger mutex,
// rcl_logging_rosout_init_publisher_for_node could be decoupled from there and be called
// here directly.
ret = rcl_node_init(
rcl_node.get(),
node_name.c_str(), namespace_.c_str(),
context_->get_rcl_context().get(), &rcl_node_options);
}
// TODO(ivanpauno): /rosout Qos should be reconfigurable.
ret = rcl_node_init(
rcl_node.get(),
node_name.c_str(), namespace_.c_str(),
context_->get_rcl_context().get(), &rcl_node_options);
if (ret != RCL_RET_OK) {
if (ret == RCL_RET_NODE_INVALID_NAME) {
rcl_reset_error(); // discard rcl_node_init error
@@ -114,13 +112,29 @@ NodeBase::NodeBase(
throw_from_rcl_error(ret, "failed to initialize rcl node");
}
// The initialization for the rosout publisher
if (rcl_logging_rosout_enabled() && rcl_node_options.enable_rosout) {
std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
ret = rcl_logging_rosout_init_publisher_for_node(rcl_node.get());
if (ret != RCL_RET_OK) {
throw_from_rcl_error(ret, "failed to initialize rosout publisher");
}
}
node_handle_.reset(
rcl_node.release(),
[logging_mutex](rcl_node_t * node) -> void {
std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
// TODO(ivanpauno): Instead of mutually excluding rcl_node_fini with the global logger mutex,
// rcl_logging_rosout_fini_publisher_for_node could be decoupled from there and be called
// here directly.
[logging_mutex, rcl_node_options](rcl_node_t * node) -> void {
{
std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
if (rcl_logging_rosout_enabled() && rcl_node_options.enable_rosout) {
rcl_ret_t ret = rcl_logging_rosout_fini_publisher_for_node(node);
if (ret != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Error in destruction of rosout publisher: %s", rcl_get_error_string().str);
}
}
}
if (rcl_node_fini(node) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",

View File

@@ -498,6 +498,50 @@ NodeGraph::count_subscribers(const std::string & topic_name) const
return count;
}
size_t
NodeGraph::count_clients(const std::string & service_name) const
{
auto rcl_node_handle = node_base_->get_rcl_node_handle();
auto fqdn = rclcpp::expand_topic_or_service_name(
service_name,
rcl_node_get_name(rcl_node_handle),
rcl_node_get_namespace(rcl_node_handle),
true);
size_t count;
auto ret = rcl_count_clients(rcl_node_handle, fqdn.c_str(), &count);
if (ret != RMW_RET_OK) {
// *INDENT-OFF*
throw std::runtime_error(
std::string("could not count clients: ") + rmw_get_error_string().str);
// *INDENT-ON*
}
return count;
}
size_t
NodeGraph::count_services(const std::string & service_name) const
{
auto rcl_node_handle = node_base_->get_rcl_node_handle();
auto fqdn = rclcpp::expand_topic_or_service_name(
service_name,
rcl_node_get_name(rcl_node_handle),
rcl_node_get_namespace(rcl_node_handle),
true);
size_t count;
auto ret = rcl_count_services(rcl_node_handle, fqdn.c_str(), &count);
if (ret != RMW_RET_OK) {
// *INDENT-OFF*
throw std::runtime_error(
std::string("could not count services: ") + rmw_get_error_string().str);
// *INDENT-ON*
}
return count;
}
const rcl_guard_condition_t *
NodeGraph::get_graph_guard_condition() const
{

View File

@@ -1038,37 +1038,50 @@ NodeParameters::list_parameters(const std::vector<std::string> & prefixes, uint6
// TODO(mikaelarguedas) define parameter separator different from "/" to avoid ambiguity
// using "." for now
const char * separator = ".";
for (auto & kv : parameters_) {
bool get_all = (prefixes.size() == 0) &&
((depth == rcl_interfaces::srv::ListParameters::Request::DEPTH_RECURSIVE) ||
(static_cast<uint64_t>(std::count(kv.first.begin(), kv.first.end(), *separator)) < depth));
bool prefix_matches = std::any_of(
prefixes.cbegin(), prefixes.cend(),
[&kv, &depth, &separator](const std::string & prefix) {
if (kv.first == prefix) {
return true;
} else if (kv.first.find(prefix + separator) == 0) {
size_t length = prefix.length();
std::string substr = kv.first.substr(length);
// Cast as unsigned integer to avoid warning
return (depth == rcl_interfaces::srv::ListParameters::Request::DEPTH_RECURSIVE) ||
(static_cast<uint64_t>(std::count(substr.begin(), substr.end(), *separator)) < depth);
}
return false;
});
if (get_all || prefix_matches) {
result.names.push_back(kv.first);
size_t last_separator = kv.first.find_last_of(separator);
if (std::string::npos != last_separator) {
std::string prefix = kv.first.substr(0, last_separator);
if (
std::find(result.prefixes.cbegin(), result.prefixes.cend(), prefix) ==
result.prefixes.cend())
{
result.prefixes.push_back(prefix);
auto separators_less_than_depth = [&depth, &separator](const std::string & str) -> bool {
return static_cast<uint64_t>(std::count(str.begin(), str.end(), *separator)) < depth;
};
bool recursive = (prefixes.size() == 0) &&
(depth == rcl_interfaces::srv::ListParameters::Request::DEPTH_RECURSIVE);
for (const std::pair<const std::string, ParameterInfo> & kv : parameters_) {
if (!recursive) {
bool get_all = (prefixes.size() == 0) && separators_less_than_depth(kv.first);
if (!get_all) {
bool prefix_matches = std::any_of(
prefixes.cbegin(), prefixes.cend(),
[&kv, &depth, &separator, &separators_less_than_depth](const std::string & prefix) {
if (kv.first == prefix) {
return true;
} else if (kv.first.find(prefix + separator) == 0) {
if (depth == rcl_interfaces::srv::ListParameters::Request::DEPTH_RECURSIVE) {
return true;
}
std::string substr = kv.first.substr(prefix.length() + 1);
return separators_less_than_depth(substr);
}
return false;
});
if (!prefix_matches) {
continue;
}
}
}
result.names.push_back(kv.first);
size_t last_separator = kv.first.find_last_of(separator);
if (std::string::npos != last_separator) {
std::string prefix = kv.first.substr(0, last_separator);
if (
std::find(result.prefixes.cbegin(), result.prefixes.cend(), prefix) ==
result.prefixes.cend())
{
result.prefixes.push_back(prefix);
}
}
}
return result;
}

View File

@@ -32,8 +32,7 @@ NodeServices::add_service(
{
if (group) {
if (!node_base_->callback_group_in_node(group)) {
// TODO(jacquelinekay): use custom exception
throw std::runtime_error("Cannot create service, group not in node.");
throw rclcpp::exceptions::MissingGroupNodeException("service");
}
} else {
group = node_base_->get_default_callback_group();
@@ -58,8 +57,7 @@ NodeServices::add_client(
{
if (group) {
if (!node_base_->callback_group_in_node(group)) {
// TODO(jacquelinekay): use custom exception
throw std::runtime_error("Cannot create client, group not in node.");
throw rclcpp::exceptions::MissingGroupNodeException("client");
}
} else {
group = node_base_->get_default_callback_group();

View File

@@ -34,8 +34,7 @@ NodeTimers::add_timer(
{
if (callback_group) {
if (!node_base_->callback_group_in_node(callback_group)) {
// TODO(jacquelinekay): use custom exception
throw std::runtime_error("Cannot create timer, group not in node.");
throw rclcpp::exceptions::MissingGroupNodeException("timer");
}
} else {
callback_group = node_base_->get_default_callback_group();
@@ -50,7 +49,7 @@ NodeTimers::add_timer(
std::string("failed to notify wait set on timer creation: ") + ex.what());
}
TRACEPOINT(
TRACETOOLS_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

@@ -58,7 +58,7 @@ NodeTopics::add_publisher(
// Assign to a group.
if (callback_group) {
if (!node_base_->callback_group_in_node(callback_group)) {
throw std::runtime_error("Cannot create publisher, callback group not in node.");
throw rclcpp::exceptions::MissingGroupNodeException("publisher");
}
} else {
callback_group = node_base_->get_default_callback_group();
@@ -97,8 +97,7 @@ NodeTopics::add_subscription(
// Assign to a group.
if (callback_group) {
if (!node_base_->callback_group_in_node(callback_group)) {
// TODO(jacquelinekay): use custom exception
throw std::runtime_error("Cannot create subscription, callback group not in node.");
throw rclcpp::exceptions::MissingGroupNodeException("subscription");
}
} else {
callback_group = node_base_->get_default_callback_group();

View File

@@ -84,23 +84,31 @@ public:
}
if (enabled) {
auto rcl_node = node_base->get_rcl_node_handle();
rcl_ret_t rcl_ret = rcl_node_type_description_service_init(rcl_node);
auto * rcl_node = node_base->get_rcl_node_handle();
std::shared_ptr<rcl_service_t> rcl_srv(
new rcl_service_t,
[rcl_node, logger = this->logger_](rcl_service_t * service)
{
if (rcl_service_fini(service, rcl_node) != RCL_RET_OK) {
RCLCPP_ERROR(
logger,
"Error in destruction of rcl service handle [~/get_type_description]: %s",
rcl_get_error_string().str);
rcl_reset_error();
}
delete service;
});
*rcl_srv = rcl_get_zero_initialized_service();
rcl_ret_t rcl_ret = rcl_node_type_description_service_init(rcl_srv.get(), rcl_node);
if (rcl_ret != RCL_RET_OK) {
RCLCPP_ERROR(
logger_, "Failed to initialize ~/get_type_description_service: %s",
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](
@@ -124,18 +132,6 @@ public:
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(

View File

@@ -32,8 +32,7 @@ NodeWaitables::add_waitable(
{
if (group) {
if (!node_base_->callback_group_in_node(group)) {
// TODO(jacobperron): use custom exception
throw std::runtime_error("Cannot create waitable, group not in node.");
throw rclcpp::exceptions::MissingGroupNodeException("waitable");
}
} else {
group = node_base_->get_default_callback_group();

View File

@@ -129,8 +129,7 @@ ParameterValue::ParameterValue(const rcl_interfaces::msg::ParameterValue & value
case PARAMETER_NOT_SET:
break;
default:
// TODO(wjwwood): use custom exception
throw std::runtime_error("Unknown type: " + std::to_string(value.type));
throw rclcpp::exceptions::UnknownTypeError(std::to_string(value.type));
}
}

View File

@@ -384,3 +384,22 @@ 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_);
}

106
rclcpp/src/rclcpp/rate.cpp Normal file
View File

@@ -0,0 +1,106 @@
// 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 "rclcpp/rate.hpp"
#include <chrono>
#include <stdexcept>
namespace rclcpp
{
Rate::Rate(
const double rate, Clock::SharedPtr clock)
: clock_(clock), period_(0, 0), last_interval_(clock_->now())
{
if (rate <= 0.0) {
throw std::invalid_argument{"rate must be greater than 0"};
}
period_ = Duration::from_seconds(1.0 / rate);
}
Rate::Rate(
const Duration & period, Clock::SharedPtr clock)
: clock_(clock), period_(period), last_interval_(clock_->now())
{
if (period <= Duration(0, 0)) {
throw std::invalid_argument{"period must be greater than 0"};
}
}
bool
Rate::sleep()
{
// Time coming into sleep
auto now = clock_->now();
// Time of next interval
auto next_interval = last_interval_ + period_;
// Detect backwards time flow
if (now < last_interval_) {
// Best thing to do is to set the next_interval to now + period
next_interval = now + period_;
}
// Update the interval
last_interval_ += period_;
// If the time_to_sleep is negative or zero, don't sleep
if (next_interval <= now) {
// If an entire cycle was missed then reset next interval.
// This might happen if the loop took more than a cycle.
// Or if time jumps forward.
if (now > next_interval + period_) {
last_interval_ = now + period_;
}
// Either way do not sleep and return false
return false;
}
// Calculate the time to sleep
auto time_to_sleep = next_interval - now;
// Sleep (will get interrupted by ctrl-c, may not sleep full time)
clock_->sleep_for(time_to_sleep);
return true;
}
bool
Rate::is_steady() const
{
return clock_->get_clock_type() == RCL_STEADY_TIME;
}
rcl_clock_type_t
Rate::get_type() const
{
return clock_->get_clock_type();
}
void
Rate::reset()
{
last_interval_ = clock_->now();
}
std::chrono::nanoseconds
Rate::period() const
{
return std::chrono::nanoseconds(period_.nanoseconds());
}
WallRate::WallRate(const double rate)
: Rate(rate, std::make_shared<Clock>(RCL_STEADY_TIME))
{}
WallRate::WallRate(const Duration & period)
: Rate(period, std::make_shared<Clock>(RCL_STEADY_TIME))
{}
} // namespace rclcpp

View File

@@ -75,7 +75,7 @@ public:
bool
install(SignalHandlerOptions signal_handler_options = SignalHandlerOptions::All);
/// Uninstall the signal handler for SIGINT/SIGTERM and join the dedicated singal handling
/// Uninstall the signal handler for SIGINT/SIGTERM and join the dedicated signal handling
/// thread.
/**
* Also restores the previous signal handler.
@@ -189,7 +189,7 @@ private:
// Whether or not a signal has been received.
std::atomic_bool signal_received_ = false;
// A thread to which singal handling tasks are deferred.
// A thread to which signal handling tasks are deferred.
std::thread signal_handler_thread_;
// A mutex used to synchronize the install() and uninstall() methods.

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
);
TRACEPOINT(rclcpp_take, static_cast<const void *>(message_out));
TRACETOOLS_TRACEPOINT(rclcpp_take, static_cast<const void *>(message_out));
if (RCL_RET_SUBSCRIPTION_TAKE_FAILED == ret) {
return false;
} else if (RCL_RET_OK != ret) {

View File

@@ -276,9 +276,9 @@ Time::operator-=(const rclcpp::Duration & rhs)
}
Time
Time::max()
Time::max(rcl_clock_type_t clock_type)
{
return Time(std::numeric_limits<int32_t>::max(), 999999999);
return Time(std::numeric_limits<int32_t>::max(), 999999999, clock_type);
}

View File

@@ -14,6 +14,7 @@
#include <memory>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>
@@ -90,7 +91,7 @@ public:
}
}
std::lock_guard<std::mutex> guard(clock_list_lock_);
associated_clocks_.push_back(clock);
associated_clocks_.insert(clock);
// Set the clock to zero unless there's a recently received message
set_clock(last_time_msg_, ros_time_active_, clock);
}
@@ -99,10 +100,8 @@ public:
void detachClock(rclcpp::Clock::SharedPtr clock)
{
std::lock_guard<std::mutex> guard(clock_list_lock_);
auto result = std::find(associated_clocks_.begin(), associated_clocks_.end(), clock);
if (result != associated_clocks_.end()) {
associated_clocks_.erase(result);
} else {
auto removed = associated_clocks_.erase(clock);
if (removed == 0) {
RCLCPP_ERROR(logger_, "failed to remove clock");
}
}
@@ -179,8 +178,8 @@ private:
// A lock to protect iterating the associated_clocks_ field.
std::mutex clock_list_lock_;
// A vector to store references to associated clocks.
std::vector<rclcpp::Clock::SharedPtr> associated_clocks_;
// An unordered_set to store references to associated clocks.
std::unordered_set<rclcpp::Clock::SharedPtr> associated_clocks_;
// Local storage of validity of ROS time
// This is needed when new clocks are added.
@@ -237,6 +236,7 @@ public:
rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock_interface,
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters_interface)
{
std::lock_guard<std::mutex> guard(node_base_lock_);
node_base_ = node_base_interface;
node_topics_ = node_topics_interface;
node_graph_ = node_graph_interface;
@@ -281,17 +281,14 @@ public:
parameter_subscription_ = rclcpp::AsyncParametersClient::on_parameter_event(
node_topics_,
[this](std::shared_ptr<const rcl_interfaces::msg::ParameterEvent> event) {
if (node_base_ != nullptr) {
this->on_parameter_event(event);
}
// Do nothing if node_base_ is nullptr because it means the TimeSource is now
// without an attached node
this->on_parameter_event(event);
});
}
// Detach the attached node
void detachNode()
{
std::lock_guard<std::mutex> guard(node_base_lock_);
// destroy_clock_sub() *must* be first here, to ensure that the executor
// can't possibly call any of the callbacks as we are cleaning up.
destroy_clock_sub();
@@ -328,6 +325,7 @@ private:
std::thread clock_executor_thread_;
// Preserve the node reference
std::mutex node_base_lock_;
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_{nullptr};
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_{nullptr};
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_{nullptr};
@@ -465,6 +463,14 @@ private:
// Callback for parameter updates
void on_parameter_event(std::shared_ptr<const rcl_interfaces::msg::ParameterEvent> event)
{
std::lock_guard<std::mutex> guard(node_base_lock_);
if (node_base_ == nullptr) {
// Do nothing if node_base_ is nullptr because it means the TimeSource is now
// without an attached node
return;
}
// Filter out events on 'use_sim_time' parameter instances in other nodes.
if (event->node != node_base_->get_fully_qualified_name()) {
return;

View File

@@ -32,7 +32,8 @@ using rclcpp::TimerBase;
TimerBase::TimerBase(
rclcpp::Clock::SharedPtr clock,
std::chrono::nanoseconds period,
rclcpp::Context::SharedPtr context)
rclcpp::Context::SharedPtr context,
bool autostart)
: clock_(clock), timer_handle_(nullptr)
{
if (nullptr == context) {
@@ -64,9 +65,9 @@ TimerBase::TimerBase(
rcl_clock_t * clock_handle = clock_->get_clock_handle();
{
std::lock_guard<std::mutex> clock_guard(clock_->get_clock_mutex());
rcl_ret_t ret = rcl_timer_init(
timer_handle_.get(), clock_handle, rcl_context.get(), period.count(), nullptr,
rcl_get_default_allocator());
rcl_ret_t ret = rcl_timer_init2(
timer_handle_.get(), clock_handle, rcl_context.get(), period.count(),
nullptr, rcl_get_default_allocator(), autostart);
if (ret != RCL_RET_OK) {
rclcpp::exceptions::throw_from_rcl_error(ret, "Couldn't initialize rcl timer handle");
}

View File

@@ -91,6 +91,44 @@ extract_type_identifier(const std::string & full_type)
return std::make_tuple(package_name, middle_module, type_name);
}
const void * get_typesupport_handle_impl(
const std::string & type,
const std::string & typesupport_identifier,
const std::string & typesupport_name,
const std::string & symbol_part_name,
const std::string & middle_module_additional,
rcpputils::SharedLibrary & library)
{
std::string package_name;
std::string middle_module;
std::string type_name;
std::tie(package_name, middle_module, type_name) = extract_type_identifier(type);
if (middle_module.empty()) {
middle_module = middle_module_additional;
}
auto mk_error = [&package_name, &type_name, &typesupport_name](auto reason) {
std::stringstream rcutils_dynamic_loading_error;
rcutils_dynamic_loading_error <<
"Something went wrong loading the typesupport library for " <<
typesupport_name << " type " << package_name <<
"/" << type_name << ". " << reason;
return rcutils_dynamic_loading_error.str();
};
try {
std::string symbol_name = typesupport_identifier + symbol_part_name +
package_name + "__" + middle_module + "__" + type_name;
const void * (* get_ts)() = nullptr;
// This will throw runtime_error if the symbol was not found.
get_ts = reinterpret_cast<decltype(get_ts)>(library.get_symbol(symbol_name));
return get_ts();
} catch (std::runtime_error &) {
throw std::runtime_error{mk_error("Library could not be found.")};
}
}
} // anonymous namespace
std::shared_ptr<rcpputils::SharedLibrary>
@@ -101,36 +139,42 @@ get_typesupport_library(const std::string & type, const std::string & typesuppor
return std::make_shared<rcpputils::SharedLibrary>(library_path);
}
const rosidl_message_type_support_t *
get_typesupport_handle(
const rosidl_message_type_support_t * get_typesupport_handle(
const std::string & type,
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library)
{
std::string package_name;
std::string middle_module;
std::string type_name;
std::tie(package_name, middle_module, type_name) = extract_type_identifier(type);
return get_message_typesupport_handle(type, typesupport_identifier, library);
}
auto mk_error = [&package_name, &type_name](auto reason) {
std::stringstream rcutils_dynamic_loading_error;
rcutils_dynamic_loading_error <<
"Something went wrong loading the typesupport library for message type " << package_name <<
"/" << type_name << ". " << reason;
return rcutils_dynamic_loading_error.str();
};
const rosidl_message_type_support_t * get_message_typesupport_handle(
const std::string & type,
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library)
{
static const std::string typesupport_name = "message";
static const std::string symbol_part_name = "__get_message_type_support_handle__";
static const std::string middle_module_additional = "msg";
try {
std::string symbol_name = typesupport_identifier + "__get_message_type_support_handle__" +
package_name + "__" + (middle_module.empty() ? "msg" : middle_module) + "__" + type_name;
return static_cast<const rosidl_message_type_support_t *>(get_typesupport_handle_impl(
type, typesupport_identifier, typesupport_name, symbol_part_name,
middle_module_additional, library
));
}
const rosidl_message_type_support_t * (* get_ts)() = nullptr;
// This will throw runtime_error if the symbol was not found.
get_ts = reinterpret_cast<decltype(get_ts)>(library.get_symbol(symbol_name));
return get_ts();
} catch (std::runtime_error &) {
throw std::runtime_error{mk_error("Library could not be found.")};
}
const rosidl_service_type_support_t * get_service_typesupport_handle(
const std::string & type,
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library)
{
static const std::string typesupport_name = "service";
static const std::string symbol_part_name = "__get_service_type_support_handle__";
static const std::string middle_module_additional = "srv";
return static_cast<const rosidl_service_type_support_t *>(get_typesupport_handle_impl(
type, typesupport_identifier, typesupport_name, symbol_part_name,
middle_module_additional, library
));
}
} // namespace rclcpp

View File

@@ -7,14 +7,12 @@ find_package(performance_test_fixture REQUIRED)
add_performance_test(benchmark_client benchmark_client.cpp)
if(TARGET benchmark_client)
target_link_libraries(benchmark_client ${PROJECT_NAME})
ament_target_dependencies(benchmark_client test_msgs rcl_interfaces)
target_link_libraries(benchmark_client ${PROJECT_NAME} ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
endif()
add_performance_test(benchmark_executor benchmark_executor.cpp)
if(TARGET benchmark_executor)
target_link_libraries(benchmark_executor ${PROJECT_NAME})
ament_target_dependencies(benchmark_executor test_msgs)
target_link_libraries(benchmark_executor ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
add_performance_test(benchmark_init_shutdown benchmark_init_shutdown.cpp)
@@ -39,6 +37,5 @@ endif()
add_performance_test(benchmark_service benchmark_service.cpp)
if(TARGET benchmark_service)
target_link_libraries(benchmark_service ${PROJECT_NAME})
ament_target_dependencies(benchmark_service test_msgs rcl_interfaces)
target_link_libraries(benchmark_service ${PROJECT_NAME} ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
endif()

View File

@@ -34,71 +34,38 @@ if(TARGET test_exceptions)
target_link_libraries(test_exceptions ${PROJECT_NAME} mimick)
endif()
# Increasing timeout because connext can take a long time to destroy nodes
# TODO(brawner) remove when destroying Node for Connext is resolved. See:
# https://github.com/ros2/rclcpp/issues/1250
ament_add_gtest(
test_allocator_memory_strategy
strategies/test_allocator_memory_strategy.cpp
TIMEOUT 360)
ament_add_gtest(test_allocator_memory_strategy strategies/test_allocator_memory_strategy.cpp)
if(TARGET test_allocator_memory_strategy)
ament_target_dependencies(test_allocator_memory_strategy
"rcl"
"test_msgs"
)
target_link_libraries(test_allocator_memory_strategy ${PROJECT_NAME})
target_link_libraries(test_allocator_memory_strategy ${PROJECT_NAME} rcpputils::rcpputils ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_message_pool_memory_strategy strategies/test_message_pool_memory_strategy.cpp)
if(TARGET test_message_pool_memory_strategy)
ament_target_dependencies(test_message_pool_memory_strategy
"rcl"
"test_msgs"
)
target_link_libraries(test_message_pool_memory_strategy ${PROJECT_NAME})
target_link_libraries(test_message_pool_memory_strategy ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_any_service_callback test_any_service_callback.cpp)
if(TARGET test_any_service_callback)
ament_target_dependencies(test_any_service_callback
"test_msgs"
)
target_link_libraries(test_any_service_callback ${PROJECT_NAME})
target_link_libraries(test_any_service_callback ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_any_subscription_callback test_any_subscription_callback.cpp)
if(TARGET test_any_subscription_callback)
ament_target_dependencies(test_any_subscription_callback
"test_msgs"
)
target_link_libraries(test_any_subscription_callback ${PROJECT_NAME})
target_link_libraries(test_any_subscription_callback ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_client test_client.cpp)
if(TARGET test_client)
ament_target_dependencies(test_client
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_client ${PROJECT_NAME} mimick)
target_link_libraries(test_client ${PROJECT_NAME} mimick ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_copy_all_parameter_values test_copy_all_parameter_values.cpp)
if(TARGET test_copy_all_parameter_values)
target_link_libraries(test_copy_all_parameter_values ${PROJECT_NAME})
endif()
ament_add_gtest(test_create_timer test_create_timer.cpp)
if(TARGET test_create_timer)
ament_target_dependencies(test_create_timer
"rcl_interfaces"
"rmw"
"rcl"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_create_timer ${PROJECT_NAME})
target_include_directories(test_create_timer PRIVATE ./)
endif()
ament_add_gtest(test_create_subscription test_create_subscription.cpp)
if(TARGET test_create_subscription)
target_link_libraries(test_create_subscription ${PROJECT_NAME})
ament_target_dependencies(test_create_subscription
"test_msgs"
)
target_link_libraries(test_create_subscription ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
function(test_add_callback_groups_to_executor_for_rmw_implementation)
set(rmw_implementation_env_var RMW_IMPLEMENTATION=${rmw_implementation})
@@ -107,32 +74,17 @@ function(test_add_callback_groups_to_executor_for_rmw_implementation)
TIMEOUT 120
)
if(TARGET test_add_callback_groups_to_executor${target_suffix})
target_link_libraries(test_add_callback_groups_to_executor${target_suffix} ${PROJECT_NAME})
ament_target_dependencies(test_add_callback_groups_to_executor${target_suffix}
"test_msgs"
)
target_link_libraries(test_add_callback_groups_to_executor${target_suffix} ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
endfunction()
call_for_each_rmw_implementation(test_add_callback_groups_to_executor_for_rmw_implementation)
ament_add_gtest(test_expand_topic_or_service_name test_expand_topic_or_service_name.cpp)
if(TARGET test_expand_topic_or_service_name)
ament_target_dependencies(test_expand_topic_or_service_name
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_expand_topic_or_service_name ${PROJECT_NAME} mimick)
target_link_libraries(test_expand_topic_or_service_name ${PROJECT_NAME} mimick rcl::rcl rmw::rmw)
endif()
ament_add_gtest(test_function_traits test_function_traits.cpp)
if(TARGET test_function_traits)
target_include_directories(test_function_traits PUBLIC ../../include)
ament_target_dependencies(test_function_traits
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_function_traits ${PROJECT_NAME})
endif()
ament_add_gtest(
test_future_return_code
@@ -142,72 +94,33 @@ if(TARGET test_future_return_code)
endif()
ament_add_gmock(test_intra_process_manager test_intra_process_manager.cpp)
if(TARGET test_intra_process_manager)
ament_target_dependencies(test_intra_process_manager
"rcl"
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_intra_process_manager ${PROJECT_NAME})
target_link_libraries(test_intra_process_manager ${PROJECT_NAME} ${rcl_interfaces_TARGETS} rmw::rmw)
endif()
ament_add_gmock(test_intra_process_manager_with_allocators test_intra_process_manager_with_allocators.cpp)
if(TARGET test_intra_process_manager_with_allocators)
ament_target_dependencies(test_intra_process_manager_with_allocators
"test_msgs"
)
target_link_libraries(test_intra_process_manager_with_allocators ${PROJECT_NAME})
target_link_libraries(test_intra_process_manager_with_allocators ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_ring_buffer_implementation test_ring_buffer_implementation.cpp)
if(TARGET test_ring_buffer_implementation)
ament_target_dependencies(test_ring_buffer_implementation
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_ring_buffer_implementation ${PROJECT_NAME})
endif()
ament_add_gtest(test_intra_process_buffer test_intra_process_buffer.cpp)
if(TARGET test_intra_process_buffer)
ament_target_dependencies(test_intra_process_buffer
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_intra_process_buffer ${PROJECT_NAME})
endif()
ament_add_gtest(test_loaned_message test_loaned_message.cpp)
ament_target_dependencies(test_loaned_message
"test_msgs"
)
target_link_libraries(test_loaned_message ${PROJECT_NAME} mimick)
target_link_libraries(test_loaned_message ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
ament_add_gtest(test_memory_strategy test_memory_strategy.cpp)
ament_target_dependencies(test_memory_strategy
"test_msgs"
)
target_link_libraries(test_memory_strategy ${PROJECT_NAME})
target_link_libraries(test_memory_strategy ${PROJECT_NAME} ${test_msgs_TARGETS})
ament_add_gtest(test_message_memory_strategy test_message_memory_strategy.cpp)
ament_target_dependencies(test_message_memory_strategy
"test_msgs"
)
target_link_libraries(test_message_memory_strategy ${PROJECT_NAME})
target_link_libraries(test_message_memory_strategy ${PROJECT_NAME} ${test_msgs_TARGETS})
ament_add_gtest(test_node test_node.cpp TIMEOUT 240)
if(TARGET test_node)
ament_target_dependencies(test_node
"rcl_interfaces"
"rcpputils"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_node ${PROJECT_NAME} mimick)
target_link_libraries(test_node ${PROJECT_NAME} mimick rcpputils::rcpputils rmw::rmw ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_node_interfaces__get_node_interfaces
@@ -218,7 +131,7 @@ endif()
ament_add_gtest(test_node_interfaces__node_base
node_interfaces/test_node_base.cpp)
if(TARGET test_node_interfaces__node_base)
target_link_libraries(test_node_interfaces__node_base ${PROJECT_NAME} mimick)
target_link_libraries(test_node_interfaces__node_base ${PROJECT_NAME} mimick rcl::rcl rmw::rmw)
endif()
ament_add_gtest(test_node_interfaces__node_clock
node_interfaces/test_node_clock.cpp)
@@ -229,48 +142,42 @@ ament_add_gtest(test_node_interfaces__node_graph
node_interfaces/test_node_graph.cpp
TIMEOUT 120)
if(TARGET test_node_interfaces__node_graph)
ament_target_dependencies(
test_node_interfaces__node_graph
"test_msgs")
target_link_libraries(test_node_interfaces__node_graph ${PROJECT_NAME} mimick)
target_link_libraries(test_node_interfaces__node_graph ${PROJECT_NAME} mimick rcl::rcl ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_node_interfaces__node_interfaces
node_interfaces/test_node_interfaces.cpp)
if(TARGET test_node_interfaces__node_interfaces)
target_link_libraries(test_node_interfaces__node_interfaces ${PROJECT_NAME} mimick)
target_link_libraries(test_node_interfaces__node_interfaces ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_parameters
node_interfaces/test_node_parameters.cpp)
if(TARGET test_node_interfaces__node_parameters)
target_link_libraries(test_node_interfaces__node_parameters ${PROJECT_NAME} mimick)
target_link_libraries(test_node_interfaces__node_parameters ${PROJECT_NAME} mimick rcpputils::rcpputils)
endif()
ament_add_gtest(test_node_interfaces__node_services
node_interfaces/test_node_services.cpp)
if(TARGET test_node_interfaces__node_services)
target_link_libraries(test_node_interfaces__node_services ${PROJECT_NAME} mimick)
target_link_libraries(test_node_interfaces__node_services ${PROJECT_NAME} mimick rcl::rcl)
endif()
ament_add_gtest(test_node_interfaces__node_timers
node_interfaces/test_node_timers.cpp)
if(TARGET test_node_interfaces__node_timers)
target_link_libraries(test_node_interfaces__node_timers ${PROJECT_NAME} mimick)
target_link_libraries(test_node_interfaces__node_timers ${PROJECT_NAME} mimick rcl::rcl)
endif()
ament_add_gtest(test_node_interfaces__node_topics
node_interfaces/test_node_topics.cpp)
if(TARGET test_node_interfaces__node_topics)
ament_target_dependencies(
test_node_interfaces__node_topics
"test_msgs")
target_link_libraries(test_node_interfaces__node_topics ${PROJECT_NAME} mimick)
target_link_libraries(test_node_interfaces__node_topics ${PROJECT_NAME} mimick rcl::rcl ${test_msgs_TARGETS})
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)
target_link_libraries(test_node_interfaces__node_type_descriptions ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_waitables
node_interfaces/test_node_waitables.cpp)
if(TARGET test_node_interfaces__node_waitables)
target_link_libraries(test_node_interfaces__node_waitables ${PROJECT_NAME} mimick)
target_link_libraries(test_node_interfaces__node_waitables ${PROJECT_NAME} mimick rcl::rcl)
endif()
ament_add_gtest(test_node_interfaces__test_template_utils # Compile time test
node_interfaces/detail/test_template_utils.cpp)
@@ -301,82 +208,43 @@ endif()
ament_add_gtest(test_node_global_args test_node_global_args.cpp)
if(TARGET test_node_global_args)
ament_target_dependencies(test_node_global_args
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_node_global_args ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_options test_node_options.cpp)
if(TARGET test_node_options)
ament_target_dependencies(test_node_options "rcl")
target_link_libraries(test_node_options ${PROJECT_NAME} mimick)
target_link_libraries(test_node_options ${PROJECT_NAME} mimick rcl::rcl)
endif()
ament_add_gtest(test_init_options test_init_options.cpp)
if(TARGET test_init_options)
ament_target_dependencies(test_init_options "rcl")
target_link_libraries(test_init_options ${PROJECT_NAME} mimick)
target_link_libraries(test_init_options ${PROJECT_NAME} mimick rcl::rcl)
endif()
ament_add_gmock(test_parameter_client test_parameter_client.cpp)
if(TARGET test_parameter_client)
ament_target_dependencies(test_parameter_client
"rcl_interfaces"
)
target_link_libraries(test_parameter_client ${PROJECT_NAME})
target_link_libraries(test_parameter_client ${PROJECT_NAME} ${rcl_interfaces_TARGETS})
endif()
ament_add_gtest(test_parameter_service test_parameter_service.cpp)
if(TARGET test_parameter_service)
ament_target_dependencies(test_parameter_service
"rcl_interfaces"
)
target_link_libraries(test_parameter_service ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_events_filter test_parameter_events_filter.cpp)
if(TARGET test_parameter_events_filter)
ament_target_dependencies(test_parameter_events_filter
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_parameter_events_filter ${PROJECT_NAME})
target_link_libraries(test_parameter_events_filter ${PROJECT_NAME} ${rcl_interfaces_TARGETS})
endif()
ament_add_gtest(test_parameter test_parameter.cpp)
if(TARGET test_parameter)
ament_target_dependencies(test_parameter
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_parameter ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_event_handler test_parameter_event_handler.cpp)
if(TARGET test_parameter_event_handler)
ament_target_dependencies(test_parameter_event_handler
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_parameter_event_handler ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_map test_parameter_map.cpp)
if(TARGET test_parameter_map)
target_link_libraries(test_parameter_map ${PROJECT_NAME})
target_link_libraries(test_parameter_map ${PROJECT_NAME} rcl::rcl rcl_yaml_param_parser::rcl_yaml_param_parser rcutils::rcutils)
endif()
ament_add_gtest(test_publisher test_publisher.cpp TIMEOUT 120)
if(TARGET test_publisher)
ament_target_dependencies(test_publisher
"rcl"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_publisher ${PROJECT_NAME} mimick)
target_link_libraries(test_publisher ${PROJECT_NAME} mimick rcl::rcl rcutils::rcutils ${test_msgs_TARGETS})
endif()
set(append_library_dirs "${CMAKE_CURRENT_BINARY_DIR}")
@@ -406,32 +274,22 @@ ament_add_gtest(test_subscription_publisher_with_same_type_adapter test_subscrip
APPEND_LIBRARY_DIRS "${append_library_dirs}"
)
if(TARGET test_subscription_publisher_with_same_type_adapter)
ament_target_dependencies(test_subscription_publisher_with_same_type_adapter
"statistics_msgs"
)
target_link_libraries(test_subscription_publisher_with_same_type_adapter
${PROJECT_NAME}
${cpp_typesupport_target})
${cpp_typesupport_target}
${statistics_msgs_TARGETS}
)
endif()
ament_add_gtest(test_publisher_subscription_count_api test_publisher_subscription_count_api.cpp)
if(TARGET test_publisher_subscription_count_api)
ament_target_dependencies(test_publisher_subscription_count_api
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_publisher_subscription_count_api ${PROJECT_NAME})
target_link_libraries(test_publisher_subscription_count_api ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_qos test_qos.cpp)
if(TARGET test_qos)
ament_target_dependencies(test_qos
"rmw"
)
target_link_libraries(test_qos
${PROJECT_NAME}
rmw::rmw
)
endif()
function(test_generic_pubsub_for_rmw_implementation)
@@ -440,12 +298,7 @@ function(test_generic_pubsub_for_rmw_implementation)
ENV ${rmw_implementation_env_var}
)
if(TARGET test_generic_pubsub${target_suffix})
target_link_libraries(test_generic_pubsub${target_suffix} ${PROJECT_NAME})
ament_target_dependencies(test_generic_pubsub${target_suffix}
"rcpputils"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_generic_pubsub${target_suffix} ${PROJECT_NAME} rcl::rcl ${test_msgs_TARGETS})
endif()
endfunction()
call_for_each_rmw_implementation(test_generic_pubsub_for_rmw_implementation)
@@ -456,153 +309,79 @@ function(test_qos_event_for_rmw_implementation)
ENV ${rmw_implementation_env_var}
)
if(TARGET test_qos_event${target_suffix})
target_link_libraries(test_qos_event${target_suffix} ${PROJECT_NAME} mimick)
ament_target_dependencies(test_qos_event${target_suffix}
"rmw"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_qos_event${target_suffix} ${PROJECT_NAME} mimick rcutils::rcutils rmw::rmw ${test_msgs_TARGETS})
endif()
endfunction()
call_for_each_rmw_implementation(test_qos_event_for_rmw_implementation)
ament_add_gmock(test_qos_overriding_options test_qos_overriding_options.cpp)
if(TARGET test_qos_overriding_options)
target_link_libraries(test_qos_overriding_options
${PROJECT_NAME}
)
target_link_libraries(test_qos_overriding_options ${PROJECT_NAME})
endif()
ament_add_gmock(test_qos_parameters test_qos_parameters.cpp)
if(TARGET test_qos_parameters)
target_link_libraries(test_qos_parameters
${PROJECT_NAME}
)
target_link_libraries(test_qos_parameters ${PROJECT_NAME})
endif()
ament_add_gtest(test_rate test_rate.cpp)
if(TARGET test_rate)
ament_target_dependencies(test_rate
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_rate
${PROJECT_NAME}
)
target_link_libraries(test_rate ${PROJECT_NAME})
endif()
ament_add_gtest(test_serialized_message_allocator test_serialized_message_allocator.cpp)
if(TARGET test_serialized_message_allocator)
ament_target_dependencies(test_serialized_message_allocator
test_msgs
)
target_link_libraries(test_serialized_message_allocator
${PROJECT_NAME}
)
target_link_libraries(test_serialized_message_allocator ${PROJECT_NAME} rcl::rcl ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_serialized_message test_serialized_message.cpp)
if(TARGET test_serialized_message)
ament_target_dependencies(test_serialized_message
test_msgs
)
target_link_libraries(test_serialized_message
${PROJECT_NAME}
)
target_link_libraries(test_serialized_message ${PROJECT_NAME} rcpputils::rcpputils ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_service test_service.cpp)
if(TARGET test_service)
ament_target_dependencies(test_service
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_service ${PROJECT_NAME} mimick)
target_link_libraries(test_service ${PROJECT_NAME} mimick ${rcl_interfaces_TARGES} ${test_msgs_TARGETS})
endif()
ament_add_gmock(test_service_introspection test_service_introspection.cpp)
if(TARGET test_service)
ament_target_dependencies(test_service_introspection
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_service_introspection ${PROJECT_NAME} mimick)
if(TARGET test_service_introspection)
target_link_libraries(test_service_introspection ${PROJECT_NAME} mimick ${service_msgs_TARGETS} ${test_msgs_TARGETS})
endif()
# Creating and destroying nodes is slow with Connext, so this needs larger timeout.
ament_add_gtest(test_subscription test_subscription.cpp TIMEOUT 120)
if(TARGET test_subscription)
ament_target_dependencies(test_subscription
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_subscription ${PROJECT_NAME} mimick)
target_link_libraries(test_subscription ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_subscription_publisher_count_api test_subscription_publisher_count_api.cpp)
if(TARGET test_subscription_publisher_count_api)
ament_target_dependencies(test_subscription_publisher_count_api
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_subscription_publisher_count_api ${PROJECT_NAME})
target_link_libraries(test_subscription_publisher_count_api ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_subscription_traits test_subscription_traits.cpp)
if(TARGET test_subscription_traits)
ament_target_dependencies(test_subscription_traits
"rcl"
"test_msgs"
)
target_link_libraries(test_subscription_traits ${PROJECT_NAME})
target_link_libraries(test_subscription_traits ${PROJECT_NAME} rcl::rcl ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_type_support test_type_support.cpp)
if(TARGET test_type_support)
ament_target_dependencies(test_type_support
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_type_support ${PROJECT_NAME})
target_link_libraries(test_type_support ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
ament_add_gmock(test_typesupport_helpers test_typesupport_helpers.cpp)
if(TARGET test_typesupport_helpers)
target_link_libraries(test_typesupport_helpers ${PROJECT_NAME})
target_link_libraries(test_typesupport_helpers ${PROJECT_NAME} rcpputils::rcpputils)
endif()
ament_add_gtest(test_find_weak_nodes test_find_weak_nodes.cpp)
if(TARGET test_find_weak_nodes)
ament_target_dependencies(test_find_weak_nodes
"rcl"
)
target_link_libraries(test_find_weak_nodes ${PROJECT_NAME})
endif()
ament_add_gtest(test_externally_defined_services test_externally_defined_services.cpp)
ament_target_dependencies(test_externally_defined_services
"rcl"
"test_msgs"
)
target_link_libraries(test_externally_defined_services ${PROJECT_NAME})
target_link_libraries(test_externally_defined_services ${PROJECT_NAME} rcl::rcl ${test_msgs_TARGETS})
ament_add_gtest(test_duration test_duration.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_duration)
ament_target_dependencies(test_duration
"rcl")
target_link_libraries(test_duration ${PROJECT_NAME})
target_link_libraries(test_duration ${PROJECT_NAME} rcl::rcl)
endif()
ament_add_gtest(test_logger test_logger.cpp)
target_link_libraries(test_logger ${PROJECT_NAME})
target_link_libraries(test_logger ${PROJECT_NAME} rcutils::rcutils)
ament_add_gmock(test_logging test_logging.cpp)
target_link_libraries(test_logging ${PROJECT_NAME})
target_link_libraries(test_logging ${PROJECT_NAME} rcutils::rcutils)
ament_add_gmock(test_context test_context.cpp)
target_link_libraries(test_context ${PROJECT_NAME})
@@ -610,134 +389,96 @@ target_link_libraries(test_context ${PROJECT_NAME})
ament_add_gtest(test_time test_time.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_time)
ament_target_dependencies(test_time
"rcl")
target_link_libraries(test_time ${PROJECT_NAME})
target_link_libraries(test_time ${PROJECT_NAME} rcl::rcl rcutils::rcutils)
endif()
ament_add_gtest(test_timer test_timer.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_timer)
ament_target_dependencies(test_timer
"rcl")
target_link_libraries(test_timer ${PROJECT_NAME} mimick)
target_link_libraries(test_timer ${PROJECT_NAME} mimick rcl::rcl)
endif()
ament_add_gtest(test_timers_manager test_timers_manager.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_timers_manager)
ament_target_dependencies(test_timers_manager
"rcl")
target_link_libraries(test_timers_manager ${PROJECT_NAME} mimick)
target_link_libraries(test_timers_manager ${PROJECT_NAME})
endif()
ament_add_gtest(test_time_source test_time_source.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_time_source)
ament_target_dependencies(test_time_source
"rcl")
target_link_libraries(test_time_source ${PROJECT_NAME})
target_link_libraries(test_time_source ${PROJECT_NAME} rcl::rcl)
endif()
ament_add_gtest(test_utilities test_utilities.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_utilities)
ament_target_dependencies(test_utilities
"rcl")
target_link_libraries(test_utilities ${PROJECT_NAME} mimick)
target_link_libraries(test_utilities ${PROJECT_NAME} mimick rcl::rcl)
endif()
ament_add_gtest(test_wait_for_message test_wait_for_message.cpp)
if(TARGET test_wait_for_message)
ament_target_dependencies(test_wait_for_message
"test_msgs")
target_link_libraries(test_wait_for_message ${PROJECT_NAME})
target_link_libraries(test_wait_for_message ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_logger_service test_logger_service.cpp)
if(TARGET test_logger_service)
ament_target_dependencies(test_logger_service
"rcl_interfaces")
target_link_libraries(test_logger_service ${PROJECT_NAME})
target_link_libraries(test_logger_service ${PROJECT_NAME} ${rcl_interfaces_TARGETS})
endif()
ament_add_gtest(test_interface_traits test_interface_traits.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_interface_traits)
ament_target_dependencies(test_interface_traits
"rcl")
target_link_libraries(test_interface_traits ${PROJECT_NAME})
endif()
# TODO(brawner) remove when destroying Node for Connext is resolved. See:
# https://github.com/ros2/rclcpp/issues/1250
ament_add_gtest(
test_executors
executors/test_executors.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}"
TIMEOUT 180)
if(TARGET test_executors)
ament_target_dependencies(test_executors
"rcl"
"test_msgs")
target_link_libraries(test_executors ${PROJECT_NAME})
target_link_libraries(test_executors ${PROJECT_NAME} rcl::rcl ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_static_single_threaded_executor executors/test_static_single_threaded_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_static_single_threaded_executor)
ament_target_dependencies(test_static_single_threaded_executor
"test_msgs")
target_link_libraries(test_static_single_threaded_executor ${PROJECT_NAME} mimick)
target_link_libraries(test_static_single_threaded_executor ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_multi_threaded_executor executors/test_multi_threaded_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_multi_threaded_executor)
ament_target_dependencies(test_multi_threaded_executor
"rcl")
target_link_libraries(test_multi_threaded_executor ${PROJECT_NAME})
endif()
ament_add_gtest(test_static_executor_entities_collector executors/test_static_executor_entities_collector.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}" TIMEOUT 120)
if(TARGET test_static_executor_entities_collector)
ament_target_dependencies(test_static_executor_entities_collector
"rcl"
"test_msgs")
target_link_libraries(test_static_executor_entities_collector ${PROJECT_NAME} mimick)
target_link_libraries(test_static_executor_entities_collector ${PROJECT_NAME} mimick rcpputils::rcpputils ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_entities_collector executors/test_entities_collector.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}" TIMEOUT 120)
if(TARGET test_entities_collector)
ament_target_dependencies(test_entities_collector
"rcl"
"test_msgs")
target_link_libraries(test_entities_collector ${PROJECT_NAME} mimick)
target_link_libraries(test_entities_collector ${PROJECT_NAME})
endif()
ament_add_gtest(test_executor_notify_waitable executors/test_executor_notify_waitable.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}" TIMEOUT 120)
if(TARGET test_executor_notify_waitable)
ament_target_dependencies(test_executor_notify_waitable
"rcl"
"test_msgs")
target_link_libraries(test_executor_notify_waitable ${PROJECT_NAME} mimick)
target_link_libraries(test_executor_notify_waitable ${PROJECT_NAME} mimick rcpputils::rcpputils)
endif()
ament_add_gtest(test_events_executor executors/test_events_executor.cpp TIMEOUT 5)
if(TARGET test_events_executor)
ament_target_dependencies(test_events_executor
"test_msgs")
target_link_libraries(test_events_executor ${PROJECT_NAME})
target_link_libraries(test_events_executor ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_events_queue executors/test_events_queue.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_events_queue)
ament_target_dependencies(test_events_queue
"test_msgs")
target_link_libraries(test_events_queue ${PROJECT_NAME})
endif()
@@ -750,76 +491,60 @@ endif()
ament_add_gtest(test_wait_set test_wait_set.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_wait_set)
ament_target_dependencies(test_wait_set "test_msgs")
target_link_libraries(test_wait_set ${PROJECT_NAME})
target_link_libraries(test_wait_set ${PROJECT_NAME} ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_subscription_topic_statistics topic_statistics/test_subscription_topic_statistics.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}"
)
if(TARGET test_subscription_topic_statistics)
ament_target_dependencies(test_subscription_topic_statistics
"builtin_interfaces"
"libstatistics_collector"
"rcl_interfaces"
"rcutils"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"statistics_msgs"
"test_msgs")
target_link_libraries(test_subscription_topic_statistics
${PROJECT_NAME}
${cpp_typesupport_target})
libstatistics_collector::libstatistics_collector
${statistics_msgs_TARGETS}
${test_msgs_TARGETS}
)
endif()
ament_add_gtest(test_subscription_options test_subscription_options.cpp)
if(TARGET test_subscription_options)
ament_target_dependencies(test_subscription_options "rcl")
target_link_libraries(test_subscription_options ${PROJECT_NAME})
endif()
ament_add_gtest(test_dynamic_storage wait_set_policies/test_dynamic_storage.cpp)
if(TARGET test_dynamic_storage)
ament_target_dependencies(test_dynamic_storage "rcl" "test_msgs")
target_link_libraries(test_dynamic_storage ${PROJECT_NAME})
target_link_libraries(test_dynamic_storage ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_storage_policy_common wait_set_policies/test_storage_policy_common.cpp)
if(TARGET test_storage_policy_common)
ament_target_dependencies(test_storage_policy_common "rcl" "test_msgs")
target_link_libraries(test_storage_policy_common ${PROJECT_NAME} mimick)
target_link_libraries(test_storage_policy_common ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_static_storage wait_set_policies/test_static_storage.cpp)
if(TARGET test_static_storage)
ament_target_dependencies(test_static_storage "rcl" "test_msgs")
target_link_libraries(test_static_storage ${PROJECT_NAME})
target_link_libraries(test_static_storage ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_thread_safe_synchronization wait_set_policies/test_thread_safe_synchronization.cpp)
if(TARGET test_thread_safe_synchronization)
ament_target_dependencies(test_thread_safe_synchronization "rcl" "test_msgs")
target_link_libraries(test_thread_safe_synchronization ${PROJECT_NAME})
target_link_libraries(test_thread_safe_synchronization ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_rosout_qos test_rosout_qos.cpp)
if(TARGET test_rosout_qos)
ament_target_dependencies(test_rosout_qos "rcl")
target_link_libraries(test_rosout_qos ${PROJECT_NAME})
target_link_libraries(test_rosout_qos ${PROJECT_NAME} rcl::rcl rmw::rmw)
endif()
ament_add_gtest(test_rosout_subscription test_rosout_subscription.cpp)
if(TARGET test_rosout_subscription)
ament_target_dependencies(test_rosout_subscription "rcl")
target_link_libraries(test_rosout_subscription ${PROJECT_NAME})
target_link_libraries(test_rosout_subscription ${PROJECT_NAME} ${rcl_interfaces_TARGETS})
endif()
ament_add_gtest(test_executor test_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}"
TIMEOUT 120)
if(TARGET test_executor)
ament_target_dependencies(test_executor "rcl")
target_link_libraries(test_executor ${PROJECT_NAME} mimick)
endif()
@@ -836,12 +561,7 @@ function(test_subscription_content_filter_for_rmw_implementation)
TIMEOUT 120
)
if(TARGET test_subscription_content_filter${target_suffix})
target_link_libraries(test_subscription_content_filter${target_suffix} ${PROJECT_NAME} mimick)
ament_target_dependencies(test_subscription_content_filter${target_suffix}
"rcpputils"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_subscription_content_filter${target_suffix} ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
endif()
endfunction()
call_for_each_rmw_implementation(test_subscription_content_filter_for_rmw_implementation)

View File

@@ -43,11 +43,6 @@ public:
TEST_F(TestEventsExecutor, run_pub_sub)
{
// rmw_connextdds doesn't support events-executor
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
auto node = std::make_shared<rclcpp::Node>("node");
bool msg_received = false;
@@ -65,7 +60,7 @@ TEST_F(TestEventsExecutor, run_pub_sub)
executor.add_node(node);
bool spin_exited = false;
std::thread spinner([&spin_exited, &executor, this]() {
std::thread spinner([&spin_exited, &executor]() {
executor.spin();
spin_exited = true;
});
@@ -80,8 +75,6 @@ TEST_F(TestEventsExecutor, run_pub_sub)
!spin_exited &&
(std::chrono::high_resolution_clock::now() - start < 1s))
{
auto time = std::chrono::high_resolution_clock::now() - start;
auto time_msec = std::chrono::duration_cast<std::chrono::milliseconds>(time);
std::this_thread::sleep_for(25ms);
}
@@ -95,11 +88,6 @@ TEST_F(TestEventsExecutor, run_pub_sub)
TEST_F(TestEventsExecutor, run_clients_servers)
{
// rmw_connextdds doesn't support events-executor
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
auto node = std::make_shared<rclcpp::Node>("node");
bool request_received = false;
@@ -119,7 +107,7 @@ TEST_F(TestEventsExecutor, run_clients_servers)
executor.add_node(node);
bool spin_exited = false;
std::thread spinner([&spin_exited, &executor, this]() {
std::thread spinner([&spin_exited, &executor]() {
executor.spin();
spin_exited = true;
});
@@ -153,11 +141,6 @@ TEST_F(TestEventsExecutor, run_clients_servers)
TEST_F(TestEventsExecutor, spin_once_max_duration_timeout)
{
// rmw_connextdds doesn't support events-executor
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
auto node = std::make_shared<rclcpp::Node>("node");
EventsExecutor executor;
@@ -190,11 +173,6 @@ TEST_F(TestEventsExecutor, spin_once_max_duration_timeout)
TEST_F(TestEventsExecutor, spin_once_max_duration_timer)
{
// rmw_connextdds doesn't support events-executor
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
auto node = std::make_shared<rclcpp::Node>("node");
EventsExecutor executor;
@@ -226,11 +204,6 @@ TEST_F(TestEventsExecutor, spin_once_max_duration_timer)
TEST_F(TestEventsExecutor, spin_some_max_duration)
{
// rmw_connextdds doesn't support events-executor
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
{
auto node = std::make_shared<rclcpp::Node>("node");
@@ -277,11 +250,6 @@ TEST_F(TestEventsExecutor, spin_some_max_duration)
TEST_F(TestEventsExecutor, spin_some_zero_duration)
{
// rmw_connextdds doesn't support events-executor
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
auto node = std::make_shared<rclcpp::Node>("node");
size_t t_runs = 0;
@@ -303,11 +271,6 @@ TEST_F(TestEventsExecutor, spin_some_zero_duration)
TEST_F(TestEventsExecutor, spin_all_max_duration)
{
// rmw_connextdds doesn't support events-executor
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
{
auto node = std::make_shared<rclcpp::Node>("node");
@@ -358,11 +321,6 @@ TEST_F(TestEventsExecutor, spin_all_max_duration)
TEST_F(TestEventsExecutor, cancel_while_timers_running)
{
// rmw_connextdds doesn't support events-executor
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
auto node = std::make_shared<rclcpp::Node>("node");
EventsExecutor executor;
@@ -388,7 +346,7 @@ TEST_F(TestEventsExecutor, cancel_while_timers_running)
});
std::thread spinner([&executor, this]() {executor.spin();});
std::thread spinner([&executor]() {executor.spin();});
std::this_thread::sleep_for(10ms);
// Call cancel while t1 callback is still being executed
@@ -402,11 +360,6 @@ TEST_F(TestEventsExecutor, cancel_while_timers_running)
TEST_F(TestEventsExecutor, cancel_while_timers_waiting)
{
// rmw_connextdds doesn't support events-executor
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
auto node = std::make_shared<rclcpp::Node>("node");
size_t t1_runs = 0;
@@ -420,7 +373,7 @@ TEST_F(TestEventsExecutor, cancel_while_timers_waiting)
executor.add_node(node);
auto start = std::chrono::steady_clock::now();
std::thread spinner([&executor, this]() {executor.spin();});
std::thread spinner([&executor]() {executor.spin();});
std::this_thread::sleep_for(10ms);
executor.cancel();
@@ -435,11 +388,6 @@ TEST_F(TestEventsExecutor, destroy_entities)
// This test fails on Windows! We skip it for now
GTEST_SKIP();
// rmw_connextdds doesn't support events-executor
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
// Create a publisher node and start publishing messages
auto node_pub = std::make_shared<rclcpp::Node>("node_pub");
auto publisher = node_pub->create_publisher<test_msgs::msg::Empty>("topic", rclcpp::QoS(10));
@@ -447,7 +395,7 @@ TEST_F(TestEventsExecutor, destroy_entities)
2ms, [&]() {publisher->publish(std::make_unique<test_msgs::msg::Empty>());});
EventsExecutor executor_pub;
executor_pub.add_node(node_pub);
std::thread spinner([&executor_pub, this]() {executor_pub.spin();});
std::thread spinner([&executor_pub]() {executor_pub.spin();});
// Create a node with two different subscriptions to the topic
auto node_sub = std::make_shared<rclcpp::Node>("node_sub");
@@ -485,11 +433,6 @@ std::string * g_sub_log_msg;
std::promise<void> * g_log_msgs_promise;
TEST_F(TestEventsExecutor, test_default_incompatible_qos_callbacks)
{
// rmw_connextdds doesn't support events-executor
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
auto node = std::make_shared<rclcpp::Node>("node");
rcutils_logging_output_handler_t original_output_handler = rcutils_logging_get_output_handler();

View File

@@ -22,7 +22,6 @@
#include <algorithm>
#include <atomic>
#include <chrono>
#include <future>
#include <limits>
#include <memory>
#include <string>
@@ -136,14 +135,6 @@ TYPED_TEST_SUITE(TestExecutorsStable, StandardExecutors, ExecutorTypeNames);
TYPED_TEST(TestExecutors, detachOnDestruction)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
{
ExecutorType executor;
executor.add_node(this->node);
@@ -160,14 +151,6 @@ TYPED_TEST(TestExecutors, detachOnDestruction)
TYPED_TEST(TestExecutorsStable, addTemporaryNode)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor;
{
@@ -188,14 +171,6 @@ TYPED_TEST(TestExecutorsStable, addTemporaryNode)
TYPED_TEST(TestExecutors, emptyExecutor)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor;
std::thread spinner([&]() {EXPECT_NO_THROW(executor.spin());});
std::this_thread::sleep_for(50ms);
@@ -207,14 +182,6 @@ TYPED_TEST(TestExecutors, emptyExecutor)
TYPED_TEST(TestExecutors, addNodeTwoExecutors)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor1;
ExecutorType executor2;
EXPECT_NO_THROW(executor1.add_node(this->node));
@@ -226,14 +193,6 @@ TYPED_TEST(TestExecutors, addNodeTwoExecutors)
TYPED_TEST(TestExecutors, spinWithTimer)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor;
bool timer_completed = false;
@@ -257,14 +216,6 @@ TYPED_TEST(TestExecutors, spinWithTimer)
TYPED_TEST(TestExecutors, spinWhileAlreadySpinning)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor;
executor.add_node(this->node);
@@ -292,14 +243,6 @@ TYPED_TEST(TestExecutors, spinWhileAlreadySpinning)
TYPED_TEST(TestExecutors, testSpinUntilFutureComplete)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor;
executor.add_node(this->node);
@@ -323,14 +266,6 @@ TYPED_TEST(TestExecutors, testSpinUntilFutureComplete)
TYPED_TEST(TestExecutors, testSpinUntilSharedFutureComplete)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor;
executor.add_node(this->node);
@@ -355,14 +290,6 @@ TYPED_TEST(TestExecutors, testSpinUntilSharedFutureComplete)
TYPED_TEST(TestExecutors, testSpinUntilFutureCompleteNoTimeout)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor;
executor.add_node(this->node);
@@ -410,14 +337,6 @@ TYPED_TEST(TestExecutors, testSpinUntilFutureCompleteNoTimeout)
TYPED_TEST(TestExecutors, testSpinUntilFutureCompleteWithTimeout)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor;
executor.add_node(this->node);
@@ -530,14 +449,6 @@ private:
TYPED_TEST(TestExecutors, spinAll)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor;
auto waitable_interfaces = this->node->get_node_waitables_interface();
auto my_waitable = std::make_shared<TestWaitable>();
@@ -580,14 +491,6 @@ TYPED_TEST(TestExecutors, spinAll)
TYPED_TEST(TestExecutors, spinSome)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor;
auto waitable_interfaces = this->node->get_node_waitables_interface();
auto my_waitable = std::make_shared<TestWaitable>();
@@ -630,14 +533,6 @@ TYPED_TEST(TestExecutors, spinSome)
TYPED_TEST(TestExecutors, testSpinNodeUntilFutureCompleteNodeBasePtr)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor;
std::promise<bool> promise;
@@ -654,14 +549,6 @@ TYPED_TEST(TestExecutors, testSpinNodeUntilFutureCompleteNodeBasePtr)
TYPED_TEST(TestExecutors, testSpinNodeUntilFutureCompleteNodePtr)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor;
std::promise<bool> promise;
@@ -678,14 +565,6 @@ TYPED_TEST(TestExecutors, testSpinNodeUntilFutureCompleteNodePtr)
TYPED_TEST(TestExecutors, testSpinUntilFutureCompleteInterrupted)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor;
executor.add_node(this->node);
@@ -765,6 +644,7 @@ TYPED_TEST(TestExecutors, testRaceConditionAddNode)
break;
}
total += k * (i + 42);
(void)total;
}
});
}
@@ -900,7 +780,7 @@ TYPED_TEST(TestIntraprocessExecutors, testIntraprocessRetrigger) {
// that publishers aren't continuing to publish.
// This was previously broken in that intraprocess guard conditions were only triggered on
// publish and the test was added to prevent future regressions.
const size_t kNumMessages = 100;
static constexpr size_t kNumMessages = 100;
using ExecutorType = TypeParam;
ExecutorType executor;
@@ -929,42 +809,12 @@ TYPED_TEST(TestIntraprocessExecutors, testIntraprocessRetrigger) {
// Fire a timer every 10ms up to 5 seconds waiting for subscriptions to be read.
loops = 0;
auto timer = this->node->create_wall_timer(
std::chrono::milliseconds(10), [this, &executor, &loops, &kNumMessages]() {
std::chrono::milliseconds(10), [this, &executor, &loops]() {
loops++;
if (kNumMessages == this->callback_count.load() ||
loops == 500)
{
if (kNumMessages == this->callback_count.load() || loops == 500) {
executor.cancel();
}
});
executor.spin();
EXPECT_EQ(kNumMessages, this->callback_count.load());
}
// Check spin functions with non default context
TEST(TestExecutors, testSpinWithNonDefaultContext)
{
auto non_default_context = std::make_shared<rclcpp::Context>();
non_default_context->init(0, nullptr);
{
auto node =
std::make_unique<rclcpp::Node>("node", rclcpp::NodeOptions().context(non_default_context));
EXPECT_NO_THROW(rclcpp::spin_some(node->get_node_base_interface()));
auto check_spin_until_future_complete = [&]() {
std::promise<bool> promise;
std::future<bool> future = promise.get_future();
promise.set_value(true);
auto shared_future = future.share();
auto ret = rclcpp::spin_until_future_complete(
node->get_node_base_interface(), shared_future, 1s);
EXPECT_EQ(rclcpp::FutureReturnCode::SUCCESS, ret);
};
EXPECT_NO_THROW(check_spin_until_future_complete());
}
rclcpp::shutdown(non_default_context);
}

View File

@@ -129,6 +129,9 @@ TEST_F(TestNodeGraph, construct_from_node)
EXPECT_EQ(0u, node_graph()->count_publishers("not_a_topic"));
EXPECT_EQ(0u, node_graph()->count_subscribers("not_a_topic"));
EXPECT_EQ(0u, node_graph()->count_clients("not_a_service"));
EXPECT_EQ(0u, node_graph()->count_services("not_a_service"));
EXPECT_NE(nullptr, node_graph()->get_graph_guard_condition());
// get_graph_event is non-const
@@ -534,6 +537,22 @@ TEST_F(TestNodeGraph, count_subscribers_rcl_error)
std::runtime_error("could not count subscribers: error not set"));
}
TEST_F(TestNodeGraph, count_clients_rcl_error)
{
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_count_clients, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
node_graph()->count_clients("service"),
std::runtime_error("could not count clients: error not set"));
}
TEST_F(TestNodeGraph, count_services_rcl_error)
{
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_count_services, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
node_graph()->count_services("service"),
std::runtime_error("could not count services: error not set"));
}
TEST_F(TestNodeGraph, notify_shutdown)
{
EXPECT_NO_THROW(node()->get_node_graph_interface()->notify_shutdown());

View File

@@ -95,15 +95,15 @@ TEST_F(TestNodeParameters, list_parameters)
std::find(list_result2.names.begin(), list_result2.names.end(), parameter_name),
list_result2.names.end());
// Check prefixes
// Check prefixes and the depth relative to the given prefixes
const std::string parameter_name2 = "prefix.new_parameter";
const rclcpp::ParameterValue value2(true);
const rcl_interfaces::msg::ParameterDescriptor descriptor2;
const auto added_parameter_value2 =
node_parameters->declare_parameter(parameter_name2, value2, descriptor2, false);
EXPECT_EQ(value.get<bool>(), added_parameter_value.get<bool>());
EXPECT_EQ(value2.get<bool>(), added_parameter_value2.get<bool>());
prefixes = {"prefix"};
auto list_result3 = node_parameters->list_parameters(prefixes, 2u);
auto list_result3 = node_parameters->list_parameters(prefixes, 1u);
EXPECT_EQ(1u, list_result3.names.size());
EXPECT_NE(
std::find(list_result3.names.begin(), list_result3.names.end(), parameter_name2),
@@ -116,6 +116,13 @@ TEST_F(TestNodeParameters, list_parameters)
EXPECT_NE(
std::find(list_result4.names.begin(), list_result4.names.end(), parameter_name),
list_result4.names.end());
// Return all parameters when the depth = 0
auto list_result5 = node_parameters->list_parameters(prefixes, 0u);
EXPECT_EQ(1u, list_result5.names.size());
EXPECT_NE(
std::find(list_result5.names.begin(), list_result5.names.end(), parameter_name),
list_result5.names.end());
}
TEST_F(TestNodeParameters, parameter_overrides)

View File

@@ -92,7 +92,7 @@ TEST_F(TestNodeService, add_service)
different_node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
RCLCPP_EXPECT_THROW_EQ(
node_services->add_service(service, callback_group_in_different_node),
std::runtime_error("Cannot create service, group not in node."));
rclcpp::exceptions::MissingGroupNodeException("service"));
}
TEST_F(TestNodeService, add_service_rcl_trigger_guard_condition_error)
@@ -119,7 +119,7 @@ TEST_F(TestNodeService, add_client)
different_node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
RCLCPP_EXPECT_THROW_EQ(
node_services->add_client(client, callback_group_in_different_node),
std::runtime_error("Cannot create client, group not in node."));
rclcpp::exceptions::MissingGroupNodeException("client"));
}
TEST_F(TestNodeService, add_client_rcl_trigger_guard_condition_error)

View File

@@ -75,7 +75,7 @@ TEST_F(TestNodeTimers, add_timer)
different_node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
RCLCPP_EXPECT_THROW_EQ(
node_timers->add_timer(timer, callback_group_in_different_node),
std::runtime_error("Cannot create timer, group not in node."));
rclcpp::exceptions::MissingGroupNodeException("timer"));
}
TEST_F(TestNodeTimers, add_timer_rcl_trigger_guard_condition_error)

View File

@@ -43,10 +43,9 @@ TEST_F(TestNodeTypeDescriptions, disabled_no_service)
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);
auto services = node.get_node_graph_interface()->get_service_names_and_types_by_node(
"node", "/ns");
EXPECT_TRUE(services.find("/ns/node/get_type_description") == services.end());
}
TEST_F(TestNodeTypeDescriptions, enabled_creates_service)
@@ -55,9 +54,8 @@ TEST_F(TestNodeTypeDescriptions, enabled_creates_service)
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);
auto services = node.get_node_graph_interface()->get_service_names_and_types_by_node(
"node", "/ns");
EXPECT_TRUE(services.find("/ns/node/get_type_description") != services.end());
}

View File

@@ -78,7 +78,7 @@ TEST_F(TestNodeWaitables, add_remove_waitable)
node_waitables->add_waitable(waitable, callback_group1));
RCLCPP_EXPECT_THROW_EQ(
node_waitables->add_waitable(waitable, callback_group2),
std::runtime_error("Cannot create waitable, group not in node."));
rclcpp::exceptions::MissingGroupNodeException("waitable"));
EXPECT_NO_THROW(node_waitables->remove_waitable(waitable, callback_group1));
EXPECT_NO_THROW(node_waitables->remove_waitable(waitable, callback_group2));

View File

@@ -56,18 +56,28 @@ TEST_F(TestMessagePoolMemoryStrategy, borrow_too_many) {
// Size is 1, borrowing second time should fail
RCLCPP_EXPECT_THROW_EQ(
message_memory_strategy_->borrow_message(),
std::runtime_error("Tried to access message that was still in use! Abort."));
std::runtime_error("No more free slots in the pool"));
EXPECT_NO_THROW(message_memory_strategy_->return_message(message));
}
TEST_F(TestMessagePoolMemoryStrategy, return_unrecognized) {
auto message = message_memory_strategy_->borrow_message();
ASSERT_NE(nullptr, message);
TEST_F(TestMessagePoolMemoryStrategy, borrow_hold_reference) {
{
auto message = message_memory_strategy_->borrow_message();
ASSERT_NE(nullptr, message);
auto unrecognized = std::make_shared<test_msgs::msg::Empty>();
// Unrecognized does not belong to pool
RCLCPP_EXPECT_THROW_EQ(
message_memory_strategy_->return_message(unrecognized),
std::runtime_error("Unrecognized message ptr in return_message."));
EXPECT_NO_THROW(message_memory_strategy_->return_message(message));
// Return it.
EXPECT_NO_THROW(message_memory_strategy_->return_message(message));
// But we are still holding the reference, so we expect that there is still no room in the pool.
RCLCPP_EXPECT_THROW_EQ(
message_memory_strategy_->borrow_message(),
std::runtime_error("No more free slots in the pool"));
}
// Now that we've dropped the reference (left the scope), we expect to be able to borrow again.
auto message2 = message_memory_strategy_->borrow_message();
ASSERT_NE(nullptr, message2);
EXPECT_NO_THROW(message_memory_strategy_->return_message(message2));
}

View File

@@ -99,13 +99,6 @@ TYPED_TEST_SUITE(TestAddCallbackGroupsToExecutorStable, StandardExecutors, Execu
TYPED_TEST(TestAddCallbackGroupsToExecutor, add_callback_groups)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
auto timer_callback = []() {};
@@ -155,13 +148,6 @@ TYPED_TEST(TestAddCallbackGroupsToExecutor, add_callback_groups)
TYPED_TEST(TestAddCallbackGroupsToExecutor, remove_callback_groups)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
auto timer_callback = []() {};
@@ -193,13 +179,6 @@ TYPED_TEST(TestAddCallbackGroupsToExecutor, remove_callback_groups)
TYPED_TEST(TestAddCallbackGroupsToExecutor, add_duplicate_callback_groups)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor;
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
@@ -220,13 +199,6 @@ TYPED_TEST(TestAddCallbackGroupsToExecutor, add_duplicate_callback_groups)
TYPED_TEST(TestAddCallbackGroupsToExecutor, add_callback_groups_after_add_node_to_executor)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor;
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
@@ -263,13 +235,6 @@ TYPED_TEST(TestAddCallbackGroupsToExecutor, add_callback_groups_after_add_node_t
TYPED_TEST(TestAddCallbackGroupsToExecutor, add_unallowable_callback_groups)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor;
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
@@ -307,13 +272,6 @@ TYPED_TEST(TestAddCallbackGroupsToExecutor, add_unallowable_callback_groups)
TYPED_TEST(TestAddCallbackGroupsToExecutor, one_node_many_callback_groups_many_executors)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType timer_executor;
ExecutorType sub_executor;
@@ -355,13 +313,6 @@ TYPED_TEST(TestAddCallbackGroupsToExecutor, one_node_many_callback_groups_many_e
TYPED_TEST(TestAddCallbackGroupsToExecutorStable, subscriber_triggered_to_receive_message)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
@@ -428,13 +379,6 @@ TYPED_TEST(TestAddCallbackGroupsToExecutorStable, subscriber_triggered_to_receiv
TYPED_TEST(TestAddCallbackGroupsToExecutorStable, callback_group_create_after_spin)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
@@ -481,13 +425,6 @@ TYPED_TEST(TestAddCallbackGroupsToExecutorStable, callback_group_create_after_sp
TYPED_TEST(TestAddCallbackGroupsToExecutor, remove_callback_group)
{
using ExecutorType = TypeParam;
// rmw_connextdds doesn't support events-executor
if (
std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>() &&
std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0)
{
GTEST_SKIP();
}
ExecutorType executor;
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");

View File

@@ -521,10 +521,6 @@ TEST_F(TestClient, rcl_client_response_subscription_get_actual_qos_error) {
}
TEST_F(TestClient, client_qos) {
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP() << "Skipping. The tests is known to be flaky in the rmw_connextdds.";
}
rclcpp::ServicesQoS qos_profile;
qos_profile.liveliness(rclcpp::LivelinessPolicy::Automatic);
rclcpp::Duration duration(std::chrono::nanoseconds(1));

View File

@@ -0,0 +1,88 @@
// Copyright 2023 Open Navigation LLC
//
// 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/copy_all_parameter_values.hpp"
#include "rclcpp/rclcpp.hpp"
class TestNode : public ::testing::Test
{
protected:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
};
TEST_F(TestNode, TestParamCopying)
{
auto node1 = std::make_shared<rclcpp::Node>("test_node1");
auto node2 = std::make_shared<rclcpp::Node>("test_node2");
// Tests for (1) multiple types, (2) recursion, (3) overriding values
node1->declare_parameter("Foo1", rclcpp::ParameterValue(std::string(("bar1"))));
node1->declare_parameter("Foo2", rclcpp::ParameterValue(0.123));
node1->declare_parameter("Foo", rclcpp::ParameterValue(std::string(("bar"))));
node1->declare_parameter("Foo.bar", rclcpp::ParameterValue(std::string(("steve"))));
node2->declare_parameter("Foo", rclcpp::ParameterValue(std::string(("barz2"))));
// Show Node2 is empty of Node1's parameters, but contains its own
EXPECT_FALSE(node2->has_parameter("Foo1"));
EXPECT_FALSE(node2->has_parameter("Foo2"));
EXPECT_FALSE(node2->has_parameter("Foo.bar"));
EXPECT_TRUE(node2->has_parameter("Foo"));
EXPECT_EQ(node2->get_parameter("Foo").as_string(), std::string("barz2"));
bool override = false;
rclcpp::copy_all_parameter_values(node1, node2, override);
// Test new parameters exist, of expected value, and original param is not overridden
EXPECT_TRUE(node2->has_parameter("Foo1"));
EXPECT_EQ(node2->get_parameter("Foo1").as_string(), std::string("bar1"));
EXPECT_TRUE(node2->has_parameter("Foo2"));
EXPECT_EQ(node2->get_parameter("Foo2").as_double(), 0.123);
EXPECT_TRUE(node2->has_parameter("Foo.bar"));
EXPECT_EQ(node2->get_parameter("Foo.bar").as_string(), std::string("steve"));
EXPECT_TRUE(node2->has_parameter("Foo"));
EXPECT_EQ(node2->get_parameter("Foo").as_string(), std::string("barz2"));
// Test if parameter overrides are permissible that Node2's value is overridden
override = true;
rclcpp::copy_all_parameter_values(node1, node2, override);
EXPECT_EQ(node2->get_parameter("Foo").as_string(), std::string("bar"));
}
TEST_F(TestNode, TestParamCopyingExceptions)
{
auto node1 = std::make_shared<rclcpp::Node>("test_node1");
auto node2 = std::make_shared<rclcpp::Node>("test_node2");
// Tests for Parameter value conflicts handled
node1->declare_parameter("Foo", rclcpp::ParameterValue(std::string(("bar"))));
node2->declare_parameter("Foo", rclcpp::ParameterValue(0.123));
bool override = true;
EXPECT_NO_THROW(
rclcpp::copy_all_parameter_values(node1, node2, override));
// Tests for Parameter read-only handled
node1->declare_parameter("Foo1", rclcpp::ParameterValue(std::string(("bar"))));
node2->declare_parameter("Foo1", rclcpp::ParameterValue(0.123));
EXPECT_NO_THROW(rclcpp::copy_all_parameter_values(node1, node2, override));
}

View File

@@ -193,3 +193,29 @@ TEST(TestCreateTimer, timer_function_pointer)
rclcpp::shutdown();
}
TEST(TestCreateTimer, timer_without_autostart)
{
rclcpp::init(0, nullptr);
auto node = std::make_shared<rclcpp::Node>("test_create_timer_node");
rclcpp::TimerBase::SharedPtr timer;
timer = rclcpp::create_timer(
node,
node->get_clock(),
rclcpp::Duration(0ms),
[]() {},
nullptr,
false);
EXPECT_TRUE(timer->is_canceled());
EXPECT_EQ(timer->time_until_trigger().count(), std::chrono::nanoseconds::max().count());
timer->reset();
EXPECT_LE(timer->time_until_trigger().count(), std::chrono::nanoseconds::max().count());
EXPECT_FALSE(timer->is_canceled());
timer->cancel();
rclcpp::shutdown();
}

View File

@@ -546,6 +546,40 @@ TEST_F(TestExecutor, spin_node_once_node) {
EXPECT_TRUE(spin_called);
}
TEST_F(TestExecutor, spin_node_all_base_interface) {
DummyExecutor dummy;
auto node = std::make_shared<rclcpp::Node>("node", "ns");
bool spin_called = false;
auto timer =
node->create_wall_timer(
std::chrono::milliseconds(1), [&]() {
spin_called = true;
});
// Wait for the wall timer to have expired.
std::this_thread::sleep_for(std::chrono::milliseconds(50));
EXPECT_FALSE(spin_called);
dummy.spin_node_all(node->get_node_base_interface(), std::chrono::milliseconds(50));
EXPECT_TRUE(spin_called);
}
TEST_F(TestExecutor, spin_node_all_node) {
DummyExecutor dummy;
auto node = std::make_shared<rclcpp::Node>("node", "ns");
bool spin_called = false;
auto timer =
node->create_wall_timer(
std::chrono::milliseconds(1), [&]() {
spin_called = true;
});
// Wait for the wall timer to have expired.
std::this_thread::sleep_for(std::chrono::milliseconds(50));
EXPECT_FALSE(spin_called);
dummy.spin_node_all(node, std::chrono::milliseconds(50));
EXPECT_TRUE(spin_called);
}
TEST_F(TestExecutor, spin_until_future_complete_future_already_complete) {
DummyExecutor dummy;
auto node = std::make_shared<rclcpp::Node>("node", "ns");

View File

@@ -69,7 +69,7 @@ public:
size_t counter = 0;
auto subscription = node_->create_generic_subscription(
topic_name, type, rclcpp::QoS(1),
[&counter, &messages, this](std::shared_ptr<rclcpp::SerializedMessage> message) {
[&counter, &messages, this](const std::shared_ptr<const rclcpp::SerializedMessage> message) {
T2 deserialized_message;
rclcpp::Serialization<T2> serializer;
serializer.deserialize_message(message.get(), &deserialized_message);
@@ -236,7 +236,7 @@ TEST_F(RclcppGenericNodeFixture, generic_subscription_uses_qos)
auto publisher = node_->create_publisher<test_msgs::msg::Strings>(topic_name, qos);
auto subscription = node_->create_generic_subscription(
topic_name, topic_type, qos,
[](std::shared_ptr<rclcpp::SerializedMessage>/* message */) {});
[](std::shared_ptr<const rclcpp::SerializedMessage>/* message */) {});
auto connected = [publisher, subscription]() -> bool {
return publisher->get_subscription_count() && subscription->get_publisher_count();
};
@@ -263,3 +263,49 @@ TEST_F(RclcppGenericNodeFixture, generic_publisher_uses_qos)
// It normally takes < 20ms, 5s chosen as "a very long time"
ASSERT_TRUE(wait_for(connected, 5s));
}
TEST_F(RclcppGenericNodeFixture, generic_subscription_different_callbacks)
{
using namespace std::chrono_literals;
std::string topic_name = "string_topic";
std::string topic_type = "test_msgs/msg/Strings";
rclcpp::QoS qos = rclcpp::QoS(1);
auto publisher = node_->create_publisher<test_msgs::msg::Strings>(topic_name, qos);
// Test shared_ptr for const messages
{
auto subscription = node_->create_generic_subscription(
topic_name, topic_type, qos,
[](const std::shared_ptr<const rclcpp::SerializedMessage>/* message */) {});
auto connected = [publisher, subscription]() -> bool {
return publisher->get_subscription_count() && subscription->get_publisher_count();
};
// It normally takes < 20ms, 5s chosen as "a very long time"
ASSERT_TRUE(wait_for(connected, 5s));
}
// Test unique_ptr
{
auto subscription = node_->create_generic_subscription(
topic_name, topic_type, qos,
[](std::unique_ptr<rclcpp::SerializedMessage>/* message */) {});
auto connected = [publisher, subscription]() -> bool {
return publisher->get_subscription_count() && subscription->get_publisher_count();
};
// It normally takes < 20ms, 5s chosen as "a very long time"
ASSERT_TRUE(wait_for(connected, 5s));
}
// Test message callback
{
auto subscription = node_->create_generic_subscription(
topic_name, topic_type, qos,
[](rclcpp::SerializedMessage /* message */) {});
auto connected = [publisher, subscription]() -> bool {
return publisher->get_subscription_count() && subscription->get_publisher_count();
};
// It normally takes < 20ms, 5s chosen as "a very long time"
ASSERT_TRUE(wait_for(connected, 5s));
}
}

View File

@@ -238,3 +238,75 @@ 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,18 +156,26 @@ 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
@@ -175,6 +183,8 @@ public:
MessageUniquePtr unique_msg;
std::uintptr_t message_ptr;
// count add and pop
size_t num_msgs = 0u;
};
} // namespace mock
@@ -221,6 +231,10 @@ public:
return topic_name.c_str();
}
virtual
size_t
available_capacity() const = 0;
rclcpp::QoS qos_profile;
std::string topic_name;
};
@@ -275,11 +289,17 @@ public:
}
bool
use_take_shared_method() const
use_take_shared_method() const override
{
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;
@@ -712,3 +732,91 @@ 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

@@ -3311,6 +3311,9 @@ TEST_F(TestNode, get_entity_names) {
const auto service_names_and_types = node->get_service_names_and_types();
EXPECT_EQ(service_names_and_types.end(), service_names_and_types.find("service"));
EXPECT_EQ(0u, node->count_clients("service"));
EXPECT_EQ(0u, node->count_services("service"));
const auto service_names_and_types_by_node =
node->get_service_names_and_types_by_node("node", "/ns");
EXPECT_EQ(

View File

@@ -482,7 +482,7 @@ public:
void publish_loaned_message(rclcpp::LoanedMessage<MessageT, AllocatorT> && loaned_msg)
{
this->do_loaned_message_publish(std::move(loaned_msg.release()));
this->do_loaned_message_publish(loaned_msg.release());
}
void call_default_incompatible_qos_callback(rclcpp::QOSOfferedIncompatibleQoSInfo & event) const
@@ -629,6 +629,41 @@ 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

@@ -314,11 +314,6 @@ TEST_F(TestQosEvent, add_to_wait_set) {
TEST_F(TestQosEvent, test_on_new_event_callback)
{
// rmw_connextdds doesn't support rmw_event_set_callback() interface
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
auto offered_deadline = rclcpp::Duration(std::chrono::milliseconds(1));
auto requested_deadline = rclcpp::Duration(std::chrono::milliseconds(2));
@@ -360,11 +355,6 @@ TEST_F(TestQosEvent, test_on_new_event_callback)
TEST_F(TestQosEvent, test_invalid_on_new_event_callback)
{
// rmw_connextdds doesn't support rmw_event_set_callback() interface
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
auto pub = node->create_publisher<test_msgs::msg::Empty>(topic_name, 10);
auto sub = node->create_subscription<test_msgs::msg::Empty>(topic_name, 10, message_callback);
auto dummy_cb = [](size_t count_events) {(void)count_events;};
@@ -439,11 +429,6 @@ TEST_F(TestQosEvent, test_invalid_on_new_event_callback)
TEST_F(TestQosEvent, test_pub_matched_event_by_set_event_callback)
{
// rmw_connextdds doesn't support rmw_event_set_callback() interface
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
std::atomic_size_t matched_count = 0;
rclcpp::PublisherOptions pub_options;
@@ -451,8 +436,10 @@ TEST_F(TestQosEvent, test_pub_matched_event_by_set_event_callback)
auto pub = node->create_publisher<test_msgs::msg::Empty>(
topic_name, 10, pub_options);
auto matched_event_callback = [&matched_count](size_t count) {
std::promise<void> prom;
auto matched_event_callback = [&matched_count, &prom](size_t count) {
matched_count += count;
prom.set_value();
};
pub->set_on_new_qos_event_callback(matched_event_callback, RCL_PUBLISHER_MATCHED);
@@ -460,34 +447,32 @@ TEST_F(TestQosEvent, test_pub_matched_event_by_set_event_callback)
rclcpp::executors::SingleThreadedExecutor ex;
ex.add_node(node->get_node_base_interface());
const auto timeout = std::chrono::milliseconds(200);
const auto timeout = std::chrono::seconds(10);
{
auto sub1 = node->create_subscription<test_msgs::msg::Empty>(topic_name, 10, message_callback);
ex.spin_some(timeout);
ex.spin_until_future_complete(prom.get_future(), timeout);
prom = {};
EXPECT_EQ(matched_count, static_cast<size_t>(1));
{
auto sub2 = node->create_subscription<test_msgs::msg::Empty>(
topic_name, 10, message_callback);
ex.spin_some(timeout);
ex.spin_until_future_complete(prom.get_future(), timeout);
prom = {};
EXPECT_EQ(matched_count, static_cast<size_t>(2));
}
ex.spin_some(timeout);
ex.spin_until_future_complete(prom.get_future(), timeout);
prom = {};
EXPECT_EQ(matched_count, static_cast<size_t>(3));
}
ex.spin_some(timeout);
ex.spin_until_future_complete(prom.get_future(), timeout);
EXPECT_EQ(matched_count, static_cast<size_t>(4));
}
TEST_F(TestQosEvent, test_sub_matched_event_by_set_event_callback)
{
// rmw_connextdds doesn't support rmw_event_set_callback() interface
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
std::atomic_size_t matched_count = 0;
rclcpp::SubscriptionOptions sub_options;
@@ -495,8 +480,10 @@ TEST_F(TestQosEvent, test_sub_matched_event_by_set_event_callback)
auto sub = node->create_subscription<test_msgs::msg::Empty>(
topic_name, 10, message_callback, sub_options);
auto matched_event_callback = [&matched_count](size_t count) {
std::promise<void> prom;
auto matched_event_callback = [&matched_count, &prom](size_t count) {
matched_count += count;
prom.set_value();
};
sub->set_on_new_qos_event_callback(matched_event_callback, RCL_SUBSCRIPTION_MATCHED);
@@ -504,39 +491,44 @@ TEST_F(TestQosEvent, test_sub_matched_event_by_set_event_callback)
rclcpp::executors::SingleThreadedExecutor ex;
ex.add_node(node->get_node_base_interface());
const auto timeout = std::chrono::milliseconds(200);
const auto timeout = std::chrono::seconds(10000);
{
auto pub1 = node->create_publisher<test_msgs::msg::Empty>(topic_name, 10);
ex.spin_some(timeout);
ex.spin_until_future_complete(prom.get_future(), timeout);
prom = {};
EXPECT_EQ(matched_count, static_cast<size_t>(1));
{
auto pub2 = node->create_publisher<test_msgs::msg::Empty>(topic_name, 10);
ex.spin_some(timeout);
ex.spin_until_future_complete(prom.get_future(), timeout);
prom = {};
EXPECT_EQ(matched_count, static_cast<size_t>(2));
}
ex.spin_some(timeout);
ex.spin_until_future_complete(prom.get_future(), timeout);
prom = {};
EXPECT_EQ(matched_count, static_cast<size_t>(3));
}
ex.spin_some(timeout);
ex.spin_until_future_complete(prom.get_future(), timeout);
EXPECT_EQ(matched_count, static_cast<size_t>(4));
}
TEST_F(TestQosEvent, test_pub_matched_event_by_option_event_callback)
{
rmw_matched_status_t matched_expected_result;
std::promise<void> prom;
rclcpp::PublisherOptions pub_options;
pub_options.event_callbacks.matched_callback =
[&matched_expected_result](rmw_matched_status_t & s) {
[&matched_expected_result, &prom](rmw_matched_status_t & s) {
EXPECT_EQ(s.total_count, matched_expected_result.total_count);
EXPECT_EQ(s.total_count_change, matched_expected_result.total_count_change);
EXPECT_EQ(s.current_count, matched_expected_result.current_count);
EXPECT_EQ(s.current_count_change, matched_expected_result.current_count_change);
prom.set_value();
};
auto pub = node->create_publisher<test_msgs::msg::Empty>(
@@ -551,11 +543,12 @@ TEST_F(TestQosEvent, test_pub_matched_event_by_option_event_callback)
matched_expected_result.current_count = 1;
matched_expected_result.current_count_change = 1;
const auto timeout = std::chrono::milliseconds(200);
const auto timeout = std::chrono::seconds(10);
{
auto sub = node->create_subscription<test_msgs::msg::Empty>(topic_name, 10, message_callback);
ex.spin_some(timeout);
ex.spin_until_future_complete(prom.get_future(), timeout);
prom = {};
// destroy a connected subscription
matched_expected_result.total_count = 1;
@@ -563,20 +556,22 @@ TEST_F(TestQosEvent, test_pub_matched_event_by_option_event_callback)
matched_expected_result.current_count = 0;
matched_expected_result.current_count_change = -1;
}
ex.spin_some(timeout);
ex.spin_until_future_complete(prom.get_future(), timeout);
}
TEST_F(TestQosEvent, test_sub_matched_event_by_option_event_callback)
{
rmw_matched_status_t matched_expected_result;
std::promise<void> prom;
rclcpp::SubscriptionOptions sub_options;
sub_options.event_callbacks.matched_callback =
[&matched_expected_result](rmw_matched_status_t & s) {
[&matched_expected_result, &prom](rmw_matched_status_t & s) {
EXPECT_EQ(s.total_count, matched_expected_result.total_count);
EXPECT_EQ(s.total_count_change, matched_expected_result.total_count_change);
EXPECT_EQ(s.current_count, matched_expected_result.current_count);
EXPECT_EQ(s.current_count_change, matched_expected_result.current_count_change);
prom.set_value();
};
auto sub = node->create_subscription<test_msgs::msg::Empty>(
topic_name, 10, message_callback, sub_options);
@@ -590,10 +585,11 @@ TEST_F(TestQosEvent, test_sub_matched_event_by_option_event_callback)
matched_expected_result.current_count = 1;
matched_expected_result.current_count_change = 1;
const auto timeout = std::chrono::milliseconds(200);
const auto timeout = std::chrono::seconds(10);
{
auto pub1 = node->create_publisher<test_msgs::msg::Empty>(topic_name, 10);
ex.spin_some(timeout);
ex.spin_until_future_complete(prom.get_future(), timeout);
prom = {};
// destroy a connected publisher
matched_expected_result.total_count = 1;
@@ -601,5 +597,5 @@ TEST_F(TestQosEvent, test_sub_matched_event_by_option_event_callback)
matched_expected_result.current_count = 0;
matched_expected_result.current_count_change = -1;
}
ex.spin_some(timeout);
ex.spin_until_future_complete(prom.get_future(), timeout);
}

View File

@@ -14,10 +14,13 @@
#include <gtest/gtest.h>
#include <stdexcept>
#include <string>
#include "rclcpp/rate.hpp"
#include "../utils/rclcpp_gtest_macros.hpp"
class TestRate : public ::testing::Test
{
public:
@@ -43,8 +46,23 @@ TEST_F(TestRate, rate_basics) {
auto start = std::chrono::system_clock::now();
rclcpp::Rate r(period);
EXPECT_EQ(period, r.period());
EXPECT_EQ(rclcpp::Duration(period), r.period());
// suppress deprecated warnings
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
ASSERT_FALSE(r.is_steady());
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
ASSERT_EQ(RCL_SYSTEM_TIME, r.get_type());
ASSERT_TRUE(r.sleep());
auto one = std::chrono::system_clock::now();
auto delta = one - start;
@@ -83,8 +101,25 @@ TEST_F(TestRate, wall_rate_basics) {
auto start = std::chrono::steady_clock::now();
rclcpp::WallRate r(period);
EXPECT_EQ(period, r.period());
EXPECT_EQ(rclcpp::Duration(period), r.period());
// suppress deprecated warnings
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
ASSERT_TRUE(r.is_steady());
// suppress deprecated warnings
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
ASSERT_EQ(RCL_STEADY_TIME, r.get_type());
ASSERT_TRUE(r.sleep());
auto one = std::chrono::steady_clock::now();
auto delta = one - start;
@@ -115,21 +150,221 @@ TEST_F(TestRate, wall_rate_basics) {
EXPECT_GT(epsilon, delta);
}
/*
Basic test for the deprecated GenericRate class.
*/
TEST_F(TestRate, generic_rate) {
auto period = std::chrono::milliseconds(100);
auto offset = std::chrono::milliseconds(50);
auto epsilon = std::chrono::milliseconds(1);
double overrun_ratio = 1.5;
{
auto start = std::chrono::system_clock::now();
// suppress deprecated warnings
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
rclcpp::GenericRate<std::chrono::system_clock> gr(period);
ASSERT_FALSE(gr.is_steady());
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
ASSERT_EQ(gr.get_type(), RCL_SYSTEM_TIME);
EXPECT_EQ(period, gr.period());
ASSERT_TRUE(gr.sleep());
auto one = std::chrono::system_clock::now();
auto delta = one - start;
EXPECT_LT(period, delta + epsilon);
EXPECT_GT(period * overrun_ratio, delta);
rclcpp::sleep_for(offset);
ASSERT_TRUE(gr.sleep());
auto two = std::chrono::system_clock::now();
delta = two - start;
EXPECT_LT(2 * period, delta);
EXPECT_GT(2 * period * overrun_ratio, delta);
rclcpp::sleep_for(offset);
auto two_offset = std::chrono::system_clock::now();
gr.reset();
ASSERT_TRUE(gr.sleep());
auto three = std::chrono::system_clock::now();
delta = three - two_offset;
EXPECT_LT(period, delta + epsilon);
EXPECT_GT(period * overrun_ratio, delta);
rclcpp::sleep_for(offset + period);
auto four = std::chrono::system_clock::now();
ASSERT_FALSE(gr.sleep());
auto five = std::chrono::system_clock::now();
delta = five - four;
ASSERT_TRUE(epsilon > delta);
}
{
auto start = std::chrono::steady_clock::now();
// suppress deprecated warnings
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
rclcpp::GenericRate<std::chrono::steady_clock> gr(period);
ASSERT_TRUE(gr.is_steady());
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
ASSERT_EQ(gr.get_type(), RCL_STEADY_TIME);
EXPECT_EQ(period, gr.period());
ASSERT_TRUE(gr.sleep());
auto one = std::chrono::steady_clock::now();
auto delta = one - start;
EXPECT_LT(period, delta);
EXPECT_GT(period * overrun_ratio, delta);
rclcpp::sleep_for(offset);
ASSERT_TRUE(gr.sleep());
auto two = std::chrono::steady_clock::now();
delta = two - start;
EXPECT_LT(2 * period, delta + epsilon);
EXPECT_GT(2 * period * overrun_ratio, delta);
rclcpp::sleep_for(offset);
auto two_offset = std::chrono::steady_clock::now();
gr.reset();
ASSERT_TRUE(gr.sleep());
auto three = std::chrono::steady_clock::now();
delta = three - two_offset;
EXPECT_LT(period, delta);
EXPECT_GT(period * overrun_ratio, delta);
rclcpp::sleep_for(offset + period);
auto four = std::chrono::steady_clock::now();
ASSERT_FALSE(gr.sleep());
auto five = std::chrono::steady_clock::now();
delta = five - four;
EXPECT_GT(epsilon, delta);
}
}
TEST_F(TestRate, from_double) {
{
rclcpp::WallRate rate(1.0);
EXPECT_EQ(std::chrono::seconds(1), rate.period());
rclcpp::Rate rate(1.0);
EXPECT_EQ(rclcpp::Duration(std::chrono::seconds(1)), rate.period());
}
{
rclcpp::WallRate rate(2.0);
EXPECT_EQ(std::chrono::milliseconds(500), rate.period());
rclcpp::Rate rate(2.0);
EXPECT_EQ(rclcpp::Duration(std::chrono::milliseconds(500)), rate.period());
}
{
rclcpp::WallRate rate(0.5);
EXPECT_EQ(std::chrono::seconds(2), rate.period());
EXPECT_EQ(rclcpp::Duration(std::chrono::seconds(2)), rate.period());
}
{
rclcpp::WallRate rate(4.0);
EXPECT_EQ(std::chrono::milliseconds(250), rate.period());
EXPECT_EQ(rclcpp::Duration(std::chrono::milliseconds(250)), rate.period());
}
}
TEST_F(TestRate, clock_types) {
{
rclcpp::Rate rate(1.0, std::make_shared<rclcpp::Clock>(RCL_SYSTEM_TIME));
// suppress deprecated warnings
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
EXPECT_FALSE(rate.is_steady());
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
EXPECT_EQ(RCL_SYSTEM_TIME, rate.get_type());
}
{
rclcpp::Rate rate(1.0, std::make_shared<rclcpp::Clock>(RCL_STEADY_TIME));
// suppress deprecated warnings
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
EXPECT_TRUE(rate.is_steady());
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
EXPECT_EQ(RCL_STEADY_TIME, rate.get_type());
}
{
rclcpp::Rate rate(1.0, std::make_shared<rclcpp::Clock>(RCL_ROS_TIME));
// suppress deprecated warnings
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
EXPECT_FALSE(rate.is_steady());
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
EXPECT_EQ(RCL_ROS_TIME, rate.get_type());
}
}
TEST_F(TestRate, incorrect_constuctor) {
// Constructor with 0-frequency
RCLCPP_EXPECT_THROW_EQ(
rclcpp::Rate rate(0.0),
std::invalid_argument("rate must be greater than 0"));
// Constructor with negative frequency
RCLCPP_EXPECT_THROW_EQ(
rclcpp::Rate rate(-1.0),
std::invalid_argument("rate must be greater than 0"));
// Constructor with 0-duration
RCLCPP_EXPECT_THROW_EQ(
rclcpp::Rate rate(rclcpp::Duration(0, 0)),
std::invalid_argument("period must be greater than 0"));
// Constructor with negative duration
RCLCPP_EXPECT_THROW_EQ(
rclcpp::Rate rate(rclcpp::Duration(-1, 0)),
std::invalid_argument("period must be greater than 0"));
}

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), this->rosout_msg_data.c_str());
rclcpp::get_logger(logger_name), "%s", 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, this->rosout_msg_data.c_str());
RCLCPP_INFO(child_logger, "%s", 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), this->rosout_msg_data.c_str());
RCLCPP_INFO(rclcpp::get_logger(logger_name), "%s", 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), this->rosout_msg_data.c_str());
RCLCPP_INFO(rclcpp::get_logger(logger_name), "%s", 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, this->rosout_msg_data.c_str());
RCLCPP_INFO(logger, "%s", 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, this->rosout_msg_data.c_str());
RCLCPP_INFO(logger, "%s", 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, this->rosout_msg_data.c_str());
RCLCPP_INFO(logger, "%s", 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, this->rosout_msg_data.c_str());
RCLCPP_INFO(logger, "%s", 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, this->rosout_msg_data.c_str());
RCLCPP_INFO(logger, "%s", 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,10 +171,20 @@ 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, this->rosout_msg_data.c_str());
RCLCPP_INFO(grandchild_logger, "%s", 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);
EXPECT_TRUE(future.get());
received_msg_promise = {};
}
TEST_F(TestRosoutSubscription, test_rosoutsubscription_node_rosout_disabled) {
rclcpp::NodeOptions options = rclcpp::NodeOptions().enable_rosout(false);
auto node = std::make_shared<rclcpp::Node>("my_node", options);
auto log_func = [&node] {
auto logger = node->get_logger().get_child("child");
RCLCPP_INFO(logger, "test");
};
ASSERT_NO_THROW(log_func());
}

View File

@@ -145,11 +145,6 @@ TEST(TestSerializedMessage, reserve) {
// Resize using reserve method
serialized_msg.reserve(15);
EXPECT_EQ(15u, serialized_msg.capacity());
// Use invalid value throws exception
EXPECT_THROW(
{serialized_msg.reserve(-1);},
rclcpp::exceptions::RCLBadAlloc);
}
TEST(TestSerializedMessage, serialization) {

View File

@@ -17,6 +17,8 @@
#include <chrono>
#include <functional>
#include <memory>
#include <ostream>
#include <stdexcept>
#include <string>
#include <thread>
#include <vector>
@@ -34,114 +36,28 @@ using namespace std::chrono_literals;
class TestSubscription : public ::testing::Test
{
public:
void OnMessage(test_msgs::msg::Empty::ConstSharedPtr msg)
void on_message(test_msgs::msg::Empty::ConstSharedPtr msg)
{
(void)msg;
}
protected:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
protected:
static void TearDownTestCase()
{
rclcpp::shutdown();
}
void initialize(const rclcpp::NodeOptions & node_options = rclcpp::NodeOptions())
{
node = std::make_shared<rclcpp::Node>("test_subscription", "/ns", node_options);
node_ = std::make_shared<rclcpp::Node>("test_subscription", "/ns", node_options);
}
void TearDown()
{
node.reset();
}
rclcpp::Node::SharedPtr node;
};
struct TestParameters
{
TestParameters(rclcpp::QoS qos, std::string description)
: qos(qos), description(description) {}
rclcpp::QoS qos;
std::string description;
};
std::ostream & operator<<(std::ostream & out, const TestParameters & params)
{
out << params.description;
return out;
}
class TestSubscriptionInvalidIntraprocessQos
: public TestSubscription,
public ::testing::WithParamInterface<TestParameters>
{};
class TestSubscriptionSub : public ::testing::Test
{
public:
void OnMessage(test_msgs::msg::Empty::ConstSharedPtr msg)
{
(void)msg;
}
protected:
static void SetUpTestCase()
{
}
void SetUp()
{
node = std::make_shared<rclcpp::Node>("test_subscription", "/ns");
subnode = node->create_sub_node("sub_ns");
}
void TearDown()
{
node.reset();
}
rclcpp::Node::SharedPtr node;
rclcpp::Node::SharedPtr subnode;
};
class SubscriptionClassNodeInheritance : public rclcpp::Node
{
public:
SubscriptionClassNodeInheritance()
: Node("subscription_class_node_inheritance")
{
}
void OnMessage(test_msgs::msg::Empty::ConstSharedPtr msg)
{
(void)msg;
}
void CreateSubscription()
{
auto callback = std::bind(
&SubscriptionClassNodeInheritance::OnMessage, this, std::placeholders::_1);
using test_msgs::msg::Empty;
auto sub = this->create_subscription<Empty>("topic", 10, callback);
}
};
class SubscriptionClass
{
public:
void OnMessage(test_msgs::msg::Empty::ConstSharedPtr msg)
{
(void)msg;
}
void CreateSubscription()
{
auto node = std::make_shared<rclcpp::Node>("test_subscription_member_callback", "/ns");
auto callback = std::bind(&SubscriptionClass::OnMessage, this, std::placeholders::_1);
using test_msgs::msg::Empty;
auto sub = node->create_subscription<Empty>("topic", 10, callback);
}
rclcpp::Node::SharedPtr node_;
};
/*
@@ -155,7 +71,7 @@ TEST_F(TestSubscription, construction_and_destruction) {
};
{
constexpr size_t depth = 10u;
auto sub = node->create_subscription<Empty>("topic", depth, callback);
auto sub = node_->create_subscription<Empty>("topic", depth, callback);
EXPECT_NE(nullptr, sub->get_subscription_handle());
// Converting to base class was necessary for the compiler to choose the const version of
@@ -172,40 +88,7 @@ TEST_F(TestSubscription, construction_and_destruction) {
{
ASSERT_THROW(
{
auto sub = node->create_subscription<Empty>("invalid_topic?", 10, callback);
}, rclcpp::exceptions::InvalidTopicNameError);
}
}
/*
Testing subscription construction and destruction for subnodes.
*/
TEST_F(TestSubscriptionSub, construction_and_destruction) {
using test_msgs::msg::Empty;
auto callback = [](Empty::ConstSharedPtr msg) {
(void)msg;
};
{
auto sub = subnode->create_subscription<Empty>("topic", 1, callback);
EXPECT_STREQ(sub->get_topic_name(), "/ns/sub_ns/topic");
}
{
auto sub = subnode->create_subscription<Empty>("/topic", 1, callback);
EXPECT_STREQ(sub->get_topic_name(), "/topic");
}
{
auto sub = subnode->create_subscription<Empty>("~/topic", 1, callback);
std::string expected_topic_name =
std::string(node->get_namespace()) + "/" + node->get_name() + "/topic";
EXPECT_STREQ(sub->get_topic_name(), expected_topic_name.c_str());
}
{
ASSERT_THROW(
{
auto sub = node->create_subscription<Empty>("invalid_topic?", 1, callback);
auto sub = node_->create_subscription<Empty>("invalid_topic?", 10, callback);
}, rclcpp::exceptions::InvalidTopicNameError);
}
}
@@ -218,31 +101,31 @@ TEST_F(TestSubscription, various_creation_signatures) {
using test_msgs::msg::Empty;
auto cb = [](test_msgs::msg::Empty::ConstSharedPtr) {};
{
auto sub = node->create_subscription<Empty>("topic", 1, cb);
auto sub = node_->create_subscription<Empty>("topic", 1, cb);
(void)sub;
}
{
auto sub = node->create_subscription<Empty>("topic", rclcpp::QoS(1), cb);
auto sub = node_->create_subscription<Empty>("topic", rclcpp::QoS(1), cb);
(void)sub;
}
{
auto sub =
node->create_subscription<Empty>("topic", rclcpp::QoS(rclcpp::KeepLast(1)), cb);
node_->create_subscription<Empty>("topic", rclcpp::QoS(rclcpp::KeepLast(1)), cb);
(void)sub;
}
{
auto sub =
node->create_subscription<Empty>("topic", rclcpp::QoS(rclcpp::KeepAll()), cb);
node_->create_subscription<Empty>("topic", rclcpp::QoS(rclcpp::KeepAll()), cb);
(void)sub;
}
{
auto sub = node->create_subscription<Empty>(
auto sub = node_->create_subscription<Empty>(
"topic", 42, cb, rclcpp::SubscriptionOptions());
(void)sub;
}
{
auto sub = rclcpp::create_subscription<Empty>(
node, "topic", 42, cb, rclcpp::SubscriptionOptions());
node_, "topic", 42, cb, rclcpp::SubscriptionOptions());
(void)sub;
}
{
@@ -250,40 +133,78 @@ TEST_F(TestSubscription, various_creation_signatures) {
options.allocator = std::make_shared<std::allocator<void>>();
EXPECT_NE(nullptr, options.get_allocator());
auto sub = rclcpp::create_subscription<Empty>(
node, "topic", 42, cb, options);
node_, "topic", 42, cb, options);
(void)sub;
}
{
rclcpp::SubscriptionOptionsBase options_base;
rclcpp::SubscriptionOptionsWithAllocator<std::allocator<void>> options(options_base);
auto sub = rclcpp::create_subscription<Empty>(
node, "topic", 42, cb, options);
node_, "topic", 42, cb, options);
(void)sub;
}
}
class SubscriptionClass final
{
public:
void custom_create_subscription()
{
auto node = std::make_shared<rclcpp::Node>("test_subscription_member_callback", "/ns");
auto callback = std::bind(&SubscriptionClass::on_message, this, std::placeholders::_1);
auto sub = node->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
}
private:
void on_message(test_msgs::msg::Empty::ConstSharedPtr msg)
{
(void)msg;
}
};
class SubscriptionClassNodeInheritance final : public rclcpp::Node
{
public:
SubscriptionClassNodeInheritance()
: Node("subscription_class_node_inheritance")
{
}
void custom_create_subscription()
{
auto callback = std::bind(
&SubscriptionClassNodeInheritance::on_message, this, std::placeholders::_1);
auto sub = this->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
}
private:
void on_message(test_msgs::msg::Empty::ConstSharedPtr msg)
{
(void)msg;
}
};
/*
Testing subscriptions using std::bind.
*/
TEST_F(TestSubscription, callback_bind) {
initialize();
using test_msgs::msg::Empty;
{
// Member callback for plain class
SubscriptionClass subscription_object;
subscription_object.CreateSubscription();
subscription_object.custom_create_subscription();
}
{
// Member callback for class inheriting from rclcpp::Node
SubscriptionClassNodeInheritance subscription_object;
subscription_object.CreateSubscription();
subscription_object.custom_create_subscription();
}
{
// Member callback for class inheriting from testing::Test
// Regression test for https://github.com/ros2/rclcpp/issues/479 where the TEST_F GTest macro
// was interfering with rclcpp's `function_traits`.
auto callback = std::bind(&TestSubscription::OnMessage, this, std::placeholders::_1);
auto sub = node->create_subscription<Empty>("topic", 1, callback);
auto callback = std::bind(&TestSubscription::on_message, this, std::placeholders::_1);
auto sub = node_->create_subscription<test_msgs::msg::Empty>("topic", 1, callback);
}
}
@@ -292,10 +213,9 @@ TEST_F(TestSubscription, callback_bind) {
*/
TEST_F(TestSubscription, take) {
initialize();
using test_msgs::msg::Empty;
auto do_nothing = [](std::shared_ptr<const test_msgs::msg::Empty>) {FAIL();};
{
auto sub = node->create_subscription<test_msgs::msg::Empty>("~/test_take", 1, do_nothing);
auto sub = node_->create_subscription<test_msgs::msg::Empty>("~/test_take", 1, do_nothing);
test_msgs::msg::Empty msg;
rclcpp::MessageInfo msg_info;
EXPECT_FALSE(sub->take(msg, msg_info));
@@ -303,23 +223,23 @@ TEST_F(TestSubscription, take) {
{
rclcpp::SubscriptionOptions so;
so.use_intra_process_comm = rclcpp::IntraProcessSetting::Disable;
auto sub = node->create_subscription<test_msgs::msg::Empty>("~/test_take", 1, do_nothing, so);
auto sub = node_->create_subscription<test_msgs::msg::Empty>("~/test_take", 1, do_nothing, so);
rclcpp::PublisherOptions po;
po.use_intra_process_comm = rclcpp::IntraProcessSetting::Disable;
auto pub = node->create_publisher<test_msgs::msg::Empty>("~/test_take", 1, po);
auto pub = node_->create_publisher<test_msgs::msg::Empty>("~/test_take", 1, po);
{
test_msgs::msg::Empty msg;
pub->publish(msg);
}
test_msgs::msg::Empty msg;
rclcpp::MessageInfo msg_info;
bool message_recieved = false;
bool message_received = false;
auto start = std::chrono::steady_clock::now();
do {
message_recieved = sub->take(msg, msg_info);
message_received = sub->take(msg, msg_info);
std::this_thread::sleep_for(100ms);
} while (!message_recieved && std::chrono::steady_clock::now() - start < 10s);
EXPECT_TRUE(message_recieved);
} while (!message_received && std::chrono::steady_clock::now() - start < 10s);
EXPECT_TRUE(message_received);
}
// TODO(wjwwood): figure out a good way to test the intra-process exclusion behavior.
}
@@ -329,10 +249,9 @@ TEST_F(TestSubscription, take) {
*/
TEST_F(TestSubscription, take_serialized) {
initialize();
using test_msgs::msg::Empty;
auto do_nothing = [](std::shared_ptr<const rclcpp::SerializedMessage>) {FAIL();};
{
auto sub = node->create_subscription<test_msgs::msg::Empty>("~/test_take", 1, do_nothing);
auto sub = node_->create_subscription<test_msgs::msg::Empty>("~/test_take", 1, do_nothing);
std::shared_ptr<rclcpp::SerializedMessage> msg = sub->create_serialized_message();
rclcpp::MessageInfo msg_info;
EXPECT_FALSE(sub->take_serialized(*msg, msg_info));
@@ -340,23 +259,23 @@ TEST_F(TestSubscription, take_serialized) {
{
rclcpp::SubscriptionOptions so;
so.use_intra_process_comm = rclcpp::IntraProcessSetting::Disable;
auto sub = node->create_subscription<test_msgs::msg::Empty>("~/test_take", 1, do_nothing, so);
auto sub = node_->create_subscription<test_msgs::msg::Empty>("~/test_take", 1, do_nothing, so);
rclcpp::PublisherOptions po;
po.use_intra_process_comm = rclcpp::IntraProcessSetting::Disable;
auto pub = node->create_publisher<test_msgs::msg::Empty>("~/test_take", 1, po);
auto pub = node_->create_publisher<test_msgs::msg::Empty>("~/test_take", 1, po);
{
test_msgs::msg::Empty msg;
pub->publish(msg);
}
std::shared_ptr<rclcpp::SerializedMessage> msg = sub->create_serialized_message();
rclcpp::MessageInfo msg_info;
bool message_recieved = false;
bool message_received = false;
auto start = std::chrono::steady_clock::now();
do {
message_recieved = sub->take_serialized(*msg, msg_info);
message_received = sub->take_serialized(*msg, msg_info);
std::this_thread::sleep_for(100ms);
} while (!message_recieved && std::chrono::steady_clock::now() - start < 10s);
EXPECT_TRUE(message_recieved);
} while (!message_received && std::chrono::steady_clock::now() - start < 10s);
EXPECT_TRUE(message_received);
}
}
@@ -368,7 +287,7 @@ TEST_F(TestSubscription, rcl_subscription_init_error) {
// reset() is not needed for triggering exception, just to avoid an unused return value warning
EXPECT_THROW(
node->create_subscription<test_msgs::msg::Empty>("topic", 10, callback).reset(),
node_->create_subscription<test_msgs::msg::Empty>("topic", 10, callback).reset(),
rclcpp::exceptions::RCLError);
}
@@ -380,7 +299,7 @@ TEST_F(TestSubscription, rcl_subscription_fini_error) {
// Cleanup just fails, no exception expected
EXPECT_NO_THROW(
node->create_subscription<test_msgs::msg::Empty>("topic", 10, callback).reset());
node_->create_subscription<test_msgs::msg::Empty>("topic", 10, callback).reset());
}
TEST_F(TestSubscription, rcl_subscription_get_actual_qos_error) {
@@ -389,7 +308,7 @@ TEST_F(TestSubscription, rcl_subscription_get_actual_qos_error) {
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_subscription_get_actual_qos, nullptr);
auto sub = node->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
auto sub = node_->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
RCLCPP_EXPECT_THROW_EQ(
sub->get_actual_qos(), std::runtime_error("failed to get qos settings: error not set"));
}
@@ -400,7 +319,7 @@ TEST_F(TestSubscription, rcl_take_type_erased_error) {
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_take, RCL_RET_ERROR);
auto sub = node->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
auto sub = node_->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
test_msgs::msg::Empty msg;
rclcpp::MessageInfo message_info;
@@ -413,7 +332,7 @@ TEST_F(TestSubscription, rcl_take_serialized_message_error) {
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_take_serialized_message, RCL_RET_ERROR);
auto sub = node->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
auto sub = node_->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
rclcpp::SerializedMessage msg;
rclcpp::MessageInfo message_info;
@@ -426,14 +345,14 @@ TEST_F(TestSubscription, rcl_subscription_get_publisher_count_error) {
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_subscription_get_publisher_count, RCL_RET_ERROR);
auto sub = node->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
auto sub = node_->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
EXPECT_THROW(sub->get_publisher_count(), rclcpp::exceptions::RCLError);
}
TEST_F(TestSubscription, handle_loaned_message) {
initialize();
auto callback = [](std::shared_ptr<const test_msgs::msg::Empty>) {};
auto sub = node->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
auto sub = node_->create_subscription<test_msgs::msg::Empty>("topic", 10, callback);
test_msgs::msg::Empty msg;
rclcpp::MessageInfo message_info;
@@ -448,13 +367,13 @@ TEST_F(TestSubscription, on_new_message_callback) {
using test_msgs::msg::Empty;
auto do_nothing = [](std::shared_ptr<const test_msgs::msg::Empty>) {FAIL();};
auto sub = node->create_subscription<test_msgs::msg::Empty>("~/test_take", 10, do_nothing);
auto sub = node_->create_subscription<test_msgs::msg::Empty>("~/test_take", 10, do_nothing);
std::atomic<size_t> c1 {0};
auto increase_c1_cb = [&c1](size_t count_msgs) {c1 += count_msgs;};
sub->set_on_new_message_callback(increase_c1_cb);
auto pub = node->create_publisher<test_msgs::msg::Empty>("~/test_take", 3);
auto pub = node_->create_publisher<test_msgs::msg::Empty>("~/test_take", 3);
{
test_msgs::msg::Empty msg;
pub->publish(msg);
@@ -518,13 +437,13 @@ TEST_F(TestSubscription, on_new_intra_process_message_callback) {
using test_msgs::msg::Empty;
auto do_nothing = [](std::shared_ptr<const test_msgs::msg::Empty>) {FAIL();};
auto sub = node->create_subscription<test_msgs::msg::Empty>("~/test_take", 10, do_nothing);
auto sub = node_->create_subscription<test_msgs::msg::Empty>("~/test_take", 10, do_nothing);
std::atomic<size_t> c1 {0};
auto increase_c1_cb = [&c1](size_t count_msgs) {c1 += count_msgs;};
sub->set_on_new_intra_process_message_callback(increase_c1_cb);
auto pub = node->create_publisher<test_msgs::msg::Empty>("~/test_take", 1);
auto pub = node_->create_publisher<test_msgs::msg::Empty>("~/test_take", 1);
{
test_msgs::msg::Empty msg;
pub->publish(msg);
@@ -580,80 +499,13 @@ TEST_F(TestSubscription, on_new_intra_process_message_callback) {
EXPECT_THROW(sub->set_on_new_intra_process_message_callback(invalid_cb), std::invalid_argument);
}
/*
Testing subscription with intraprocess enabled and invalid QoS
*/
TEST_P(TestSubscriptionInvalidIntraprocessQos, test_subscription_throws) {
initialize(rclcpp::NodeOptions().use_intra_process_comms(true));
rclcpp::QoS qos = GetParam().qos;
using test_msgs::msg::Empty;
{
auto callback = std::bind(
&TestSubscriptionInvalidIntraprocessQos::OnMessage,
this,
std::placeholders::_1);
ASSERT_THROW(
{auto subscription = node->create_subscription<Empty>(
"topic",
qos,
callback);},
std::invalid_argument);
}
}
/*
Testing subscription with invalid use_intra_process_comm
*/
TEST_P(TestSubscriptionInvalidIntraprocessQos, test_subscription_throws_intraprocess) {
rclcpp::SubscriptionOptionsWithAllocator<std::allocator<void>> options;
options.use_intra_process_comm = static_cast<rclcpp::IntraProcessSetting>(5);
initialize();
rclcpp::QoS qos = GetParam().qos;
auto callback = std::bind(
&TestSubscriptionInvalidIntraprocessQos::OnMessage,
this,
std::placeholders::_1);
RCLCPP_EXPECT_THROW_EQ(
{auto subscription = node->create_subscription<test_msgs::msg::Empty>(
"topic",
qos,
callback,
options);},
std::runtime_error("Unrecognized IntraProcessSetting value"));
}
static std::vector<TestParameters> invalid_qos_profiles()
{
std::vector<TestParameters> parameters;
parameters.reserve(3);
parameters.push_back(
TestParameters(
rclcpp::QoS(rclcpp::KeepLast(10)).transient_local(),
"transient_local_qos"));
parameters.push_back(
TestParameters(
rclcpp::QoS(rclcpp::KeepAll()),
"keep_all_qos"));
return parameters;
}
INSTANTIATE_TEST_SUITE_P(
TestSubscriptionThrows, TestSubscriptionInvalidIntraprocessQos,
::testing::ValuesIn(invalid_qos_profiles()),
::testing::PrintToStringParamName());
TEST_F(TestSubscription, get_network_flow_endpoints_errors) {
initialize();
const rclcpp::QoS subscription_qos(1);
auto subscription_callback = [](test_msgs::msg::Empty::ConstSharedPtr msg) {
(void)msg;
};
auto subscription = node->create_subscription<test_msgs::msg::Empty>(
auto subscription = node_->create_subscription<test_msgs::msg::Empty>(
"topic", subscription_qos, subscription_callback);
{
@@ -680,3 +532,143 @@ TEST_F(TestSubscription, get_network_flow_endpoints_errors) {
EXPECT_NO_THROW(subscription->get_network_flow_endpoints());
}
}
class TestSubscriptionSub : public ::testing::Test
{
protected:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
void SetUp()
{
node_ = std::make_shared<rclcpp::Node>("test_subscription", "/ns");
subnode_ = node_->create_sub_node("sub_ns");
}
rclcpp::Node::SharedPtr node_;
rclcpp::Node::SharedPtr subnode_;
};
/*
Testing subscription construction and destruction for subnodes.
*/
TEST_F(TestSubscriptionSub, construction_and_destruction) {
auto callback = [](test_msgs::msg::Empty::ConstSharedPtr msg) {
(void)msg;
};
{
auto sub = subnode_->create_subscription<test_msgs::msg::Empty>("topic", 1, callback);
EXPECT_STREQ(sub->get_topic_name(), "/ns/sub_ns/topic");
}
{
auto sub = subnode_->create_subscription<test_msgs::msg::Empty>("/topic", 1, callback);
EXPECT_STREQ(sub->get_topic_name(), "/topic");
}
{
auto sub = subnode_->create_subscription<test_msgs::msg::Empty>("~/topic", 1, callback);
std::string expected_topic_name =
std::string(node_->get_namespace()) + "/" + node_->get_name() + "/topic";
EXPECT_STREQ(sub->get_topic_name(), expected_topic_name.c_str());
}
{
ASSERT_THROW(
{
auto sub = node_->create_subscription<test_msgs::msg::Empty>("invalid_topic?", 1, callback);
}, rclcpp::exceptions::InvalidTopicNameError);
}
}
struct TestParameters final
{
TestParameters(rclcpp::QoS qos, std::string description)
: qos(qos), description(description) {}
rclcpp::QoS qos;
std::string description;
};
std::ostream & operator<<(std::ostream & out, const TestParameters & params)
{
out << params.description;
return out;
}
class TestSubscriptionInvalidIntraprocessQos
: public TestSubscription,
public ::testing::WithParamInterface<TestParameters>
{};
static std::vector<TestParameters> invalid_qos_profiles()
{
std::vector<TestParameters> parameters;
parameters.reserve(3);
parameters.push_back(
TestParameters(
rclcpp::QoS(rclcpp::KeepLast(10)).transient_local(),
"transient_local_qos"));
parameters.push_back(
TestParameters(
rclcpp::QoS(rclcpp::KeepAll()),
"keep_all_qos"));
return parameters;
}
INSTANTIATE_TEST_SUITE_P(
TestSubscriptionThrows, TestSubscriptionInvalidIntraprocessQos,
::testing::ValuesIn(invalid_qos_profiles()),
::testing::PrintToStringParamName());
/*
Testing subscription with intraprocess enabled and invalid QoS
*/
TEST_P(TestSubscriptionInvalidIntraprocessQos, test_subscription_throws) {
initialize(rclcpp::NodeOptions().use_intra_process_comms(true));
rclcpp::QoS qos = GetParam().qos;
{
auto callback = std::bind(
&TestSubscriptionInvalidIntraprocessQos::on_message,
this,
std::placeholders::_1);
ASSERT_THROW(
{auto subscription = node_->create_subscription<test_msgs::msg::Empty>(
"topic",
qos,
callback);},
std::invalid_argument);
}
}
/*
Testing subscription with invalid use_intra_process_comm
*/
TEST_P(TestSubscriptionInvalidIntraprocessQos, test_subscription_throws_intraprocess) {
rclcpp::SubscriptionOptionsWithAllocator<std::allocator<void>> options;
options.use_intra_process_comm = static_cast<rclcpp::IntraProcessSetting>(5);
initialize();
rclcpp::QoS qos = GetParam().qos;
auto callback = std::bind(
&TestSubscriptionInvalidIntraprocessQos::on_message,
this,
std::placeholders::_1);
RCLCPP_EXPECT_THROW_EQ(
{auto subscription = node_->create_subscription<test_msgs::msg::Empty>(
"topic",
qos,
callback,
options);},
std::runtime_error("Unrecognized IntraProcessSetting value"));
}

View File

@@ -310,25 +310,3 @@ TEST_F(CLASSNAME(TestContentFilterSubscription, RMW_IMPLEMENTATION), content_fil
}
}
}
TEST_F(
CLASSNAME(
TestContentFilterSubscription,
RMW_IMPLEMENTATION), create_two_content_filters_with_same_topic_name_and_destroy) {
// Create another content filter
auto options = rclcpp::SubscriptionOptions();
std::string filter_expression = "int32_value > %0";
std::vector<std::string> expression_parameters = {"4"};
options.content_filter_options.filter_expression = filter_expression;
options.content_filter_options.expression_parameters = expression_parameters;
auto callback = [](std::shared_ptr<const test_msgs::msg::BasicTypes>) {};
auto sub_2 = node->create_subscription<test_msgs::msg::BasicTypes>(
"content_filter_topic", qos, callback, options);
EXPECT_NE(nullptr, sub_2);
sub_2.reset();
}

Some files were not shown because too many files have changed in this diff Show More