Skip to content

Commit 962bcf9

Browse files
authored
Add message lost status event demo using rclcpp (#453)
Signed-off-by: Ivan Santiago Paunovic <[email protected]>
1 parent b6b2910 commit 962bcf9

File tree

6 files changed

+299
-0
lines changed

6 files changed

+299
-0
lines changed

quality_of_service_demo/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,33 @@ Notice that "Deadline missed" is constantly being printed even though the publis
147147
because Deadline and Liveliness QoS Policies are unrelated.
148148
**Press** `s` in the publisher's terminal again to start publishing messages again,
149149
and the "Deadline missed" messages will no longer be printed.
150+
151+
## Message lost status event demo
152+
153+
This demo shows how to get a notification when a subscription loses a message.
154+
155+
The feature is available in some rmw implementations: rmw_cyclonedds, rmw_connext.
156+
CycloneDDS partially implements the feature and it only triggers the event under some limited circumstances, thus it's recommended to try the demo with Connext.
157+
158+
To run the demo:
159+
```
160+
export RMW_IMPLEMENTATION = rmw_connext_cpp
161+
ros2 run quality_of_service_demo_cpp message_lost_listener &
162+
# -s allows specifying the message size in KiB. This argument is optional, defaults to 8192KiB.
163+
ros2 run quality_of_service_demo_cpp message_lost_talker -s 8192
164+
```
165+
166+
Example output:
167+
```
168+
[INFO] [1593021627.113051194] [message_lost_talker]: Publishing an image, sent at [1593021627.113023]
169+
[INFO] [1593021630.114633564] [message_lost_talker]: Publishing an image, sent at [1593021630.114625]
170+
[INFO] [1593021633.158548336] [message_lost_talker]: Publishing an image, sent at [1593021633.158538]
171+
[INFO] [1593021635.971678672] [MessageLostListener]: Some messages were lost:
172+
> Number of new lost messages: 1
173+
> Total number of messages lost: 1
174+
[INFO] [1593021636.130686719] [message_lost_talker]: Publishing an image, sent at [1593021636.130677]
175+
[INFO] [1593021636.601466840] [MessageLostListener]: I heard an image. Message single trip latency: [3.442907]
176+
[INFO] [1593021639.129067211] [message_lost_talker]: Publishing an image, sent at [1593021639.129058]
177+
```
178+
179+
For information about how to tune QoS settings for large messages see [DDS tuning](https://index.ros.org/doc/ros2/Troubleshooting/DDS-tuning/).

quality_of_service_demo/rclcpp/CMakeLists.txt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ endif()
1313

1414
find_package(ament_cmake REQUIRED)
1515
find_package(rclcpp REQUIRED)
16+
find_package(rclcpp_components REQUIRED)
1617
find_package(rcutils)
1718
find_package(rmw REQUIRED)
19+
find_package(sensor_msgs REQUIRED)
1820
find_package(std_msgs REQUIRED)
1921

2022
include_directories(include)
@@ -40,6 +42,31 @@ qos_demo_executable(interactive_publisher)
4042
qos_demo_executable(interactive_subscriber)
4143
qos_demo_executable(incompatible_qos)
4244

45+
add_library(message_lost SHARED
46+
src/message_lost_listener.cpp
47+
src/message_lost_talker.cpp)
48+
ament_target_dependencies(message_lost
49+
"rclcpp"
50+
"rclcpp_components"
51+
"rcutils"
52+
"sensor_msgs"
53+
)
54+
target_compile_definitions(message_lost
55+
PRIVATE "QUALITY_OF_SERVICE_DEMO_BUILDING_DLL")
56+
rclcpp_components_register_node(message_lost
57+
PLUGIN "quality_of_service_demo::MessageLostListener"
58+
EXECUTABLE message_lost_listener)
59+
rclcpp_components_register_node(message_lost
60+
PLUGIN "quality_of_service_demo::MessageLostTalker"
61+
EXECUTABLE message_lost_talker)
62+
63+
install(TARGETS
64+
message_lost
65+
ARCHIVE DESTINATION lib
66+
LIBRARY DESTINATION lib
67+
RUNTIME DESTINATION bin
68+
)
69+
4370
if(BUILD_TESTING)
4471
find_package(ament_lint_auto REQUIRED)
4572
ament_lint_auto_find_test_dependencies()
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2020 Open Source Robotics Foundation, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef QUALITY_OF_SERVICE_DEMO__VISIBILITY_CONTROL_H_
16+
#define QUALITY_OF_SERVICE_DEMO__VISIBILITY_CONTROL_H_
17+
18+
#ifdef __cplusplus
19+
extern "C"
20+
{
21+
#endif
22+
23+
// This logic was borrowed (then namespaced) from the examples on the gcc wiki:
24+
// https://gcc.gnu.org/wiki/Visibility
25+
26+
#if defined _WIN32 || defined __CYGWIN__
27+
#ifdef __GNUC__
28+
#define QUALITY_OF_SERVICE_DEMO_EXPORT __attribute__ ((dllexport))
29+
#define QUALITY_OF_SERVICE_DEMO_IMPORT __attribute__ ((dllimport))
30+
#else
31+
#define QUALITY_OF_SERVICE_DEMO_EXPORT __declspec(dllexport)
32+
#define QUALITY_OF_SERVICE_DEMO_IMPORT __declspec(dllimport)
33+
#endif
34+
#ifdef QUALITY_OF_SERVICE_DEMO_BUILDING_DLL
35+
#define QUALITY_OF_SERVICE_DEMO_PUBLIC QUALITY_OF_SERVICE_DEMO_EXPORT
36+
#else
37+
#define QUALITY_OF_SERVICE_DEMO_PUBLIC QUALITY_OF_SERVICE_DEMO_IMPORT
38+
#endif
39+
#define QUALITY_OF_SERVICE_DEMO_PUBLIC_TYPE QUALITY_OF_SERVICE_DEMO_PUBLIC
40+
#define QUALITY_OF_SERVICE_DEMO_LOCAL
41+
#else
42+
#define QUALITY_OF_SERVICE_DEMO_EXPORT __attribute__ ((visibility("default")))
43+
#define QUALITY_OF_SERVICE_DEMO_IMPORT
44+
#if __GNUC__ >= 4
45+
#define QUALITY_OF_SERVICE_DEMO_PUBLIC __attribute__ ((visibility("default")))
46+
#define QUALITY_OF_SERVICE_DEMO_LOCAL __attribute__ ((visibility("hidden")))
47+
#else
48+
#define QUALITY_OF_SERVICE_DEMO_PUBLIC
49+
#define QUALITY_OF_SERVICE_DEMO_LOCAL
50+
#endif
51+
#define QUALITY_OF_SERVICE_DEMO_PUBLIC_TYPE
52+
#endif
53+
54+
#ifdef __cplusplus
55+
}
56+
#endif
57+
58+
#endif // QUALITY_OF_SERVICE_DEMO__VISIBILITY_CONTROL_H_

quality_of_service_demo/rclcpp/package.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,20 @@
1515

1616
<build_depend>example_interfaces</build_depend>
1717
<build_depend>rclcpp</build_depend>
18+
<build_depend>rclcpp_components</build_depend>
1819
<build_depend>rcutils</build_depend>
1920
<build_depend>rmw</build_depend>
2021
<build_depend>rmw_implementation_cmake</build_depend>
22+
<build_depend>sensor_msgs</build_depend>
2123
<build_depend>std_msgs</build_depend>
2224

2325
<exec_depend>example_interfaces</exec_depend>
2426
<exec_depend>launch_ros</exec_depend>
2527
<exec_depend>rclcpp</exec_depend>
28+
<exec_depend>rclcpp_components</exec_depend>
2629
<exec_depend>rcutils</exec_depend>
2730
<exec_depend>rmw</exec_depend>
31+
<exec_depend>sensor_msgs</exec_depend>
2832
<exec_depend>std_msgs</exec_depend>
2933

3034
<test_depend>ament_lint_auto</test_depend>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2020 Open Source Robotics Foundation, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "rclcpp/rclcpp.hpp"
16+
#include "rclcpp_components/register_node_macro.hpp"
17+
18+
#include "sensor_msgs/msg/image.hpp"
19+
20+
#include "quality_of_service_demo/visibility_control.h"
21+
22+
namespace quality_of_service_demo
23+
{
24+
class MessageLostListener : public rclcpp::Node
25+
{
26+
public:
27+
QUALITY_OF_SERVICE_DEMO_PUBLIC
28+
explicit MessageLostListener(const rclcpp::NodeOptions & options)
29+
: Node("MessageLostListener", options)
30+
{
31+
auto callback =
32+
[this](const sensor_msgs::msg::Image::SharedPtr msg) -> void
33+
{
34+
rclcpp::Time now = this->get_clock()->now();
35+
auto diff = now - msg->header.stamp;
36+
RCLCPP_INFO(
37+
this->get_logger(),
38+
"I heard an image. Message single trip latency: [%f]",
39+
diff.seconds());
40+
};
41+
// Create a subscription to the topic which can be matched with one or more compatible ROS
42+
// publishers.
43+
// Note that not all publishers on the same topic with the same type will be compatible:
44+
// they must have compatible Quality of Service policies.
45+
rclcpp::SubscriptionOptions sub_opts;
46+
sub_opts.event_callbacks.message_lost_callback =
47+
[logger = this->get_logger()](rclcpp::QOSMessageLostInfo & info)
48+
{
49+
RCLCPP_INFO_STREAM(
50+
logger,
51+
"Some messages were lost:\n>\tNumber of new lost messages: " <<
52+
info.total_count_change << " \n>\tTotal number of messages lost: " <<
53+
info.total_count);
54+
};
55+
sub_ = create_subscription<sensor_msgs::msg::Image>(
56+
"message_lost_chatter", 1, callback, sub_opts);
57+
}
58+
59+
private:
60+
rclcpp::Subscription<sensor_msgs::msg::Image>::SharedPtr sub_;
61+
};
62+
63+
} // namespace quality_of_service_demo
64+
65+
RCLCPP_COMPONENTS_REGISTER_NODE(quality_of_service_demo::MessageLostListener)
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Copyright 2020 Open Source Robotics Foundation, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <chrono>
16+
#include <memory>
17+
#include <string>
18+
#include <utility>
19+
#include <vector>
20+
21+
#include "rcutils/cmdline_parser.h"
22+
23+
#include "rclcpp/rclcpp.hpp"
24+
#include "rclcpp_components/register_node_macro.hpp"
25+
26+
#include "sensor_msgs/msg/image.hpp"
27+
28+
#include "quality_of_service_demo/visibility_control.h"
29+
30+
using namespace std::chrono_literals;
31+
32+
namespace quality_of_service_demo
33+
{
34+
void print_usage()
35+
{
36+
std::cout <<
37+
"Usage: message_lost_talker [-h] [-s SIZE]\n\n"
38+
"optional arguments:\n"
39+
"\t-h: Print this help message.\n"
40+
"\t-s <message_size>: Message size in KiB, default to 8192 KiB" <<
41+
std::endl;
42+
}
43+
44+
class MessageLostTalker : public rclcpp::Node
45+
{
46+
public:
47+
QUALITY_OF_SERVICE_DEMO_PUBLIC
48+
explicit MessageLostTalker(const rclcpp::NodeOptions & options)
49+
: Node("message_lost_talker", options),
50+
message_size_(8u * 1024u * 1024u) // 8MB
51+
{
52+
const std::vector<std::string> & args = this->get_node_options().arguments();
53+
if (args.size()) {
54+
// Argument usage
55+
if (args.cend() != std::find(args.cbegin(), args.cend(), "-h")) {
56+
print_usage();
57+
// TODO(ivanpauno): Update the rclcpp_components template to be able to handle
58+
// exceptions. Raise one here, so stack unwinding happens gracefully.
59+
std::exit(0);
60+
}
61+
// Argument: message size
62+
auto opt_it = std::find(args.cbegin(), args.cend(), "-s");
63+
if (opt_it != args.cend()) {
64+
++opt_it;
65+
if (opt_it == args.cend()) {
66+
print_usage();
67+
std::cout << "\n-s must be followed by a possitive integer" << std::endl;
68+
// TODO(ivanpauno): Update the rclcpp_components template to be able to handle
69+
// exceptions. Raise one here, so stack unwinding happens gracefully.
70+
std::exit(0);
71+
}
72+
std::istringstream input_stream(*opt_it);
73+
input_stream >> message_size_;
74+
if (!input_stream) {
75+
print_usage();
76+
std::cout << "\n-s must be followed by a possitive integer, got: '" <<
77+
*opt_it << "'" << std::endl;
78+
// TODO(ivanpauno): Update the rclcpp_components template to be able to handle
79+
// exceptions. Raise one here, so stack unwinding happens gracefully.
80+
std::exit(0);
81+
}
82+
message_size_ *= 1024uL;
83+
}
84+
}
85+
auto publish_message =
86+
[this]() -> void
87+
{
88+
for (size_t i = 0; i < message_size_; ++i) {
89+
msg_.data.push_back(0);
90+
}
91+
rclcpp::Time now = this->get_clock()->now();
92+
msg_.header.stamp = now;
93+
RCLCPP_INFO(
94+
this->get_logger(),
95+
"Publishing an image, sent at [%f]",
96+
now.seconds());
97+
98+
pub_->publish(msg_);
99+
};
100+
pub_ = this->create_publisher<sensor_msgs::msg::Image>("message_lost_chatter", 1);
101+
102+
// Use a timer to schedule periodic message publishing.
103+
timer_ = this->create_wall_timer(3s, publish_message);
104+
}
105+
106+
private:
107+
size_t message_size_;
108+
sensor_msgs::msg::Image msg_;
109+
rclcpp::Publisher<sensor_msgs::msg::Image>::SharedPtr pub_;
110+
rclcpp::TimerBase::SharedPtr timer_;
111+
};
112+
113+
} // namespace quality_of_service_demo
114+
115+
RCLCPP_COMPONENTS_REGISTER_NODE(quality_of_service_demo::MessageLostTalker)

0 commit comments

Comments
 (0)