Skip to content

Commit 51042e5

Browse files
authored
Merge pull request #59 from ros-realtime/feature/exercise4-2-update
update exercise4-2
2 parents a935611 + 0ab2f7b commit 51042e5

12 files changed

+194
-41
lines changed
Binary file not shown.
Binary file not shown.
-49.2 KB
Binary file not shown.
-32.2 KB
Binary file not shown.
Binary file not shown.
Binary file not shown.
-508 KB
Binary file not shown.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#include "application_nodes.h"
2+
#include <cstdlib>
3+
#include <chrono>
4+
#include <list>
5+
#include <memory>
6+
#include <string>
7+
#include <thread>
8+
#include <vector>
9+
10+
#include "utils.h"
11+
12+
using cactus_rt::tracing::ThreadTracer;
13+
using camera_demo_interfaces::msg::FakeImage;
14+
15+
CameraProcessingNode::CameraProcessingNode(
16+
std::shared_ptr<ThreadTracer> tracer_object_detector,
17+
std::shared_ptr<ThreadTracer> tracer_data_logger
18+
) : Node("obj_detect"), tracer_object_detector_(tracer_object_detector), tracer_data_logger_(tracer_data_logger) {
19+
realtime_group_ = this->create_callback_group(
20+
rclcpp::CallbackGroupType::MutuallyExclusive
21+
);
22+
besteffort_group_ = this->create_callback_group(
23+
rclcpp::CallbackGroupType::MutuallyExclusive
24+
);
25+
26+
rclcpp::SubscriptionOptions data_logging_options;
27+
data_logging_options.callback_group = besteffort_group_;
28+
subscription_data_logger_ = this->create_subscription<FakeImage>(
29+
"/image",
30+
10,
31+
std::bind(&CameraProcessingNode::DataLoggerCallback, this, std::placeholders::_1),
32+
data_logging_options
33+
);
34+
35+
rclcpp::SubscriptionOptions obj_det_options;
36+
obj_det_options.callback_group = realtime_group_;
37+
subscription_object_detector_ = this->create_subscription<FakeImage>(
38+
"/image",
39+
10,
40+
std::bind(&CameraProcessingNode::ObjectDetectorCallback, this, std::placeholders::_1),
41+
obj_det_options
42+
);
43+
44+
publisher_ = this->create_publisher<std_msgs::msg::Int64>("/actuation", 10);
45+
46+
// initialization of random variable for DataLogger latency
47+
srand((unsigned)time(NULL));
48+
}
49+
50+
void CameraProcessingNode::ObjectDetectorCallback(const FakeImage::SharedPtr image) {
51+
// A hack to trace the message passing delay between publisher and this node
52+
auto now = cactus_rt::NowNs();
53+
tracer_object_detector_->StartSpan("MessageDelay", nullptr, image->published_at_monotonic_nanos);
54+
tracer_object_detector_->EndSpan(now);
55+
56+
{
57+
auto span = tracer_object_detector_->WithSpan("ObjectDetect");
58+
59+
WasteTime(std::chrono::microseconds(3000));
60+
61+
// Send a signal to the downstream actuation node
62+
std_msgs::msg::Int64 msg;
63+
msg.data = image->published_at_monotonic_nanos;
64+
publisher_->publish(msg);
65+
}
66+
}
67+
68+
void CameraProcessingNode::DataLoggerCallback(const FakeImage::SharedPtr image) {
69+
// A hack to trace the message passing delay between publisher and this node
70+
auto now = cactus_rt::NowNs();
71+
tracer_data_logger_->StartSpan("MessageDelay", nullptr, image->published_at_monotonic_nanos);
72+
tracer_data_logger_->EndSpan(now);
73+
74+
{
75+
auto span = tracer_data_logger_->WithSpan("DataLogger");
76+
77+
// variable duration to serialize the data between [5ms,10ms]
78+
unsigned int data_logger_latency = 5000 + (rand() % 5001);
79+
WasteTime(std::chrono::microseconds(data_logger_latency));
80+
81+
// Assume it takes about 1ms to write the data where it is blocking but yielded to the CPU.
82+
std::this_thread::sleep_for(std::chrono::microseconds(1000));
83+
}
84+
}
85+
86+
rclcpp::CallbackGroup::SharedPtr CameraProcessingNode::get_realtime_cbg() {
87+
if (!realtime_group_) {
88+
realtime_group_ = this->create_callback_group(
89+
rclcpp::CallbackGroupType::MutuallyExclusive
90+
);
91+
}
92+
return realtime_group_;
93+
}
94+
95+
rclcpp::CallbackGroup::SharedPtr CameraProcessingNode::get_besteffort_cbg() {
96+
if (!besteffort_group_) {
97+
besteffort_group_ = this->create_callback_group(
98+
rclcpp::CallbackGroupType::MutuallyExclusive
99+
);
100+
}
101+
return besteffort_group_;
102+
}
103+
104+
ActuationNode::ActuationNode(
105+
std::shared_ptr<cactus_rt::tracing::ThreadTracer> tracer
106+
) : Node("actuation"), tracer_(tracer) {
107+
subscription_ = this->create_subscription<std_msgs::msg::Int64>(
108+
"/actuation",
109+
10,
110+
std::bind(&ActuationNode::MessageCallback, this, std::placeholders::_1)
111+
);
112+
}
113+
114+
void ActuationNode::MessageCallback(const std_msgs::msg::Int64::SharedPtr published_at_timestamp) {
115+
auto now = cactus_rt::NowNs();
116+
117+
// A hack to show the end to end latency, from the moment it was published to
118+
// the moment it is received by this node.
119+
tracer_->StartSpan("EndToEndDelay", nullptr, published_at_timestamp->data);
120+
tracer_->EndSpan(now);
121+
122+
{
123+
auto span = tracer_->WithSpan("Actuation");
124+
WasteTime(std::chrono::microseconds(150));
125+
}
126+
}

exercise4-2/solutions/file_solution.cc

Whitespace-only changes.

exercise4-2/solutions/main.cc

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include <rclcpp/rclcpp.hpp>
2+
3+
#include "application_nodes.h"
4+
#include "system_nodes.h"
5+
#include "tracing.h"
6+
7+
int main(int argc, char** argv) {
8+
// initialization of ROS and DDS middleware
9+
rclcpp::init(argc, argv);
10+
11+
StartImagePublisherNode();
12+
13+
auto actuation_tracer = std::make_shared<cactus_rt::tracing::ThreadTracer>("actuation");
14+
auto actuation_node = std::make_shared<ActuationNode>(actuation_tracer);
15+
16+
auto object_detector_tracer = std::make_shared<cactus_rt::tracing::ThreadTracer>("object_detector_callback");
17+
auto data_logger_tracer = std::make_shared<cactus_rt::tracing::ThreadTracer>("data_logger_callback");
18+
auto camera_processing_node = std::make_shared<CameraProcessingNode>(object_detector_tracer, data_logger_tracer);
19+
auto data_logger_group = camera_processing_node->get_besteffort_cbg();
20+
auto object_detector_group = camera_processing_node->get_realtime_cbg();
21+
22+
StartTracing("camera_demo_4_2", "exercise4-2.perfetto");
23+
RegisterThreadTracer(actuation_tracer);
24+
RegisterThreadTracer(object_detector_tracer);
25+
RegisterThreadTracer(data_logger_tracer);
26+
27+
rclcpp::executors::SingleThreadedExecutor real_time_executor;
28+
rclcpp::executors::SingleThreadedExecutor best_effort_executor;
29+
30+
best_effort_executor.add_callback_group(data_logger_group, camera_processing_node->get_node_base_interface());
31+
real_time_executor.add_callback_group(object_detector_group, camera_processing_node->get_node_base_interface());
32+
real_time_executor.add_node(actuation_node);
33+
34+
// Launch real-time Executor in a thread
35+
std::thread real_time_thread([&real_time_executor]() {
36+
sched_param sch;
37+
sch.sched_priority = 60;
38+
if (sched_setscheduler(0, SCHED_FIFO, &sch) == -1) {
39+
perror("sched_setscheduler failed");
40+
exit(-1);
41+
}
42+
real_time_executor.spin();
43+
});
44+
45+
best_effort_executor.spin();
46+
47+
rclcpp::shutdown();
48+
StopTracing();
49+
50+
JoinImagePublisherNode();
51+
real_time_thread.join();
52+
return 0;
53+
}

exercise4-2/src/camera_demo/src/application_nodes.cc

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#include "application_nodes.h"
2-
2+
#include <cstdlib>
33
#include <chrono>
44
#include <list>
55
#include <memory>
@@ -16,32 +16,23 @@ CameraProcessingNode::CameraProcessingNode(
1616
std::shared_ptr<ThreadTracer> tracer_object_detector,
1717
std::shared_ptr<ThreadTracer> tracer_data_logger
1818
) : Node("obj_detect"), tracer_object_detector_(tracer_object_detector), tracer_data_logger_(tracer_data_logger) {
19-
realtime_group_ = this->create_callback_group(
20-
rclcpp::CallbackGroupType::MutuallyExclusive
21-
);
22-
besteffort_group_ = this->create_callback_group(
23-
rclcpp::CallbackGroupType::MutuallyExclusive
24-
);
25-
26-
rclcpp::SubscriptionOptions data_logging_options;
27-
data_logging_options.callback_group = besteffort_group_;
19+
2820
subscription_data_logger_ = this->create_subscription<FakeImage>(
2921
"/image",
3022
10,
31-
std::bind(&CameraProcessingNode::DataLoggerCallback, this, std::placeholders::_1),
32-
data_logging_options
23+
std::bind(&CameraProcessingNode::DataLoggerCallback, this, std::placeholders::_1)
3324
);
3425

35-
rclcpp::SubscriptionOptions obj_det_options;
36-
obj_det_options.callback_group = realtime_group_;
3726
subscription_object_detector_ = this->create_subscription<FakeImage>(
3827
"/image",
3928
10,
40-
std::bind(&CameraProcessingNode::ObjectDetectorCallback, this, std::placeholders::_1),
41-
obj_det_options
29+
std::bind(&CameraProcessingNode::ObjectDetectorCallback, this, std::placeholders::_1)
4230
);
4331

4432
publisher_ = this->create_publisher<std_msgs::msg::Int64>("/actuation", 10);
33+
34+
// initialization of random variable for DataLogger latency
35+
srand((unsigned)time(NULL));
4536
}
4637

4738
void CameraProcessingNode::ObjectDetectorCallback(const FakeImage::SharedPtr image) {
@@ -52,8 +43,6 @@ void CameraProcessingNode::ObjectDetectorCallback(const FakeImage::SharedPtr ima
5243

5344
{
5445
auto span = tracer_object_detector_->WithSpan("ObjectDetect");
55-
56-
// Pretend it takes 3ms to do object detection.
5746
WasteTime(std::chrono::microseconds(3000));
5847

5948
// Send a signal to the downstream actuation node
@@ -72,8 +61,9 @@ void CameraProcessingNode::DataLoggerCallback(const FakeImage::SharedPtr image)
7261
{
7362
auto span = tracer_data_logger_->WithSpan("DataLogger");
7463

75-
// Assume it takes 6ms to serialize the data which is all on the CPU
76-
WasteTime(std::chrono::microseconds(6000));
64+
// variable duration to serialize the data between [5ms,10ms]
65+
unsigned int data_logger_latency = 5000 + (rand() % 5001);
66+
WasteTime(std::chrono::microseconds(data_logger_latency));
7767

7868
// Assume it takes about 1ms to write the data where it is blocking but yielded to the CPU.
7969
std::this_thread::sleep_for(std::chrono::microseconds(1000));

exercise4-2/src/camera_demo/src/main.cc

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,31 +24,15 @@ int main(int argc, char** argv) {
2424
RegisterThreadTracer(object_detector_tracer);
2525
RegisterThreadTracer(data_logger_tracer);
2626

27-
rclcpp::executors::SingleThreadedExecutor real_time_executor;
28-
rclcpp::executors::SingleThreadedExecutor best_effort_executor;
29-
30-
best_effort_executor.add_callback_group(data_logger_group, camera_processing_node->get_node_base_interface());
31-
real_time_executor.add_callback_group(object_detector_group, camera_processing_node->get_node_base_interface());
32-
real_time_executor.add_node(actuation_node);
33-
34-
// Launch best effort thread
35-
std::thread best_effort_thread([&best_effort_executor]() {
36-
best_effort_executor.spin();
37-
});
38-
39-
// Set the priority of this realtime thread
40-
sched_param sch;
41-
sch.sched_priority = 50;
42-
if (sched_setscheduler(0, SCHED_FIFO, &sch) == -1) {
43-
perror("sched_setscheduler failed");
44-
exit(-1);
45-
}
46-
real_time_executor.spin();
27+
rclcpp::executors::SingleThreadedExecutor executor;
28+
29+
executor.add_node(camera_processing_node);
30+
executor.add_node(actuation_node);
31+
executor.spin();
4732

4833
rclcpp::shutdown();
4934
StopTracing();
5035

5136
JoinImagePublisherNode();
52-
best_effort_thread.join();
5337
return 0;
5438
}

0 commit comments

Comments
 (0)