1
+ #include < helpers/commonHelpers.hpp>
2
+ #include < helpers/graphHelpers.hpp>
3
+ #include < helpers/testPointCloud.hpp>
4
+
5
+ #include < rgl/api/extensions/ros2.h>
6
+
7
+ #include < rclcpp/rclcpp.hpp>
8
+ #include < sensor_msgs/msg/laser_scan.hpp>
9
+
10
+ class Ros2PublishLaserScanNodeTest : public RGLTest
11
+ {};
12
+
13
+ TEST_F (Ros2PublishLaserScanNodeTest, should_throw_invalid_pipeline_when_ros2_shutdown_laserscan)
14
+ {
15
+ std::vector<rgl_field_t > fields{AZIMUTH_F32, DISTANCE_F32, TIME_STAMP_F64, INTENSITY_F32};
16
+ TestPointCloud pointCloud (fields, 10 );
17
+ rgl_node_t points = pointCloud.createUsePointsNode ();
18
+
19
+ rgl_node_t yield = nullptr ;
20
+ EXPECT_RGL_SUCCESS (rgl_node_points_yield (&yield, fields.data (), fields.size ()));
21
+
22
+ rgl_node_t ros2pub = nullptr ;
23
+
24
+ EXPECT_RGL_SUCCESS (rgl_node_publish_ros2_laserscan (&ros2pub, " laserscan" , " rglFrame" ));
25
+
26
+ EXPECT_RGL_SUCCESS (rgl_graph_node_add_child (points, yield));
27
+ EXPECT_RGL_SUCCESS (rgl_graph_node_add_child (yield, ros2pub));
28
+
29
+ EXPECT_RGL_SUCCESS (rgl_graph_run (points));
30
+
31
+ rclcpp::shutdown ();
32
+ EXPECT_RGL_INVALID_PIPELINE (rgl_graph_run (points), " Unable to execute Ros2Node because ROS2 has been shut down." );
33
+ }
34
+
35
+ TEST_F (Ros2PublishLaserScanNodeTest, should_receive_sent_data)
36
+ {
37
+ const auto POINT_COUNT = 5 ;
38
+ const auto TOPIC_NAME = " rgl_test_laser_scan" ;
39
+ const auto FRAME_ID = " rgl_test_frame_id" ;
40
+ const auto NODE_NAME = " rgl_test_node" ;
41
+ const auto WAIT_TIME_SECS = 1 ;
42
+ const auto MESSAGE_REPEATS = 3 ;
43
+ const auto START_ANGLE = 0 .8f ;
44
+ const auto ANGLE_INCREMENT = 0 .11f ;
45
+ const auto TIME_INCREMENT = 0 .22f ;
46
+
47
+ TestPointCloud input ({AZIMUTH_F32, DISTANCE_F32, TIME_STAMP_F64, INTENSITY_F32}, POINT_COUNT);
48
+
49
+ // Expected data
50
+ const auto expectedAngles = generateFieldValues (
51
+ POINT_COUNT, std::function<Field<AZIMUTH_F32>::type (int )>(
52
+ [START_ANGLE, ANGLE_INCREMENT](int i) { return START_ANGLE + i * ANGLE_INCREMENT; }));
53
+ input.setFieldValues <AZIMUTH_F32>(expectedAngles);
54
+ const auto expectedTimes = generateFieldValues (POINT_COUNT, std::function<Field<TIME_STAMP_F64>::type (int )>(
55
+ [TIME_INCREMENT](int i) { return i * TIME_INCREMENT; }));
56
+ input.setFieldValues <TIME_STAMP_F64>(expectedTimes);
57
+ const auto expectedRanges = input.getFieldValues <DISTANCE_F32>();
58
+ const auto expectedIntensities = input.getFieldValues <INTENSITY_F32>();
59
+ const auto [minRange, maxRange] = std::minmax_element (expectedRanges.begin (), expectedRanges.end ());
60
+ const auto expectedScanTime = expectedTimes.at (expectedTimes.size () - 1 ) - expectedTimes.at (0 );
61
+
62
+ // Create nodes
63
+ rgl_node_t inputNode = input.createUsePointsNode (), laserScanNode = nullptr ;
64
+ ASSERT_RGL_SUCCESS (rgl_node_publish_ros2_laserscan (&laserScanNode, TOPIC_NAME, FRAME_ID));
65
+
66
+ // Connect nodes
67
+ ASSERT_RGL_SUCCESS (rgl_graph_node_add_child (inputNode, laserScanNode));
68
+
69
+ // Synchronization primitives
70
+ std::atomic<int > messageCount = 0 ;
71
+
72
+
73
+ // Create ROS2 subscriber to receive LaserScan messages on topic "laser_scan"
74
+ auto node = std::make_shared<rclcpp::Node>(NODE_NAME, rclcpp::NodeOptions{});
75
+ auto qos = rclcpp::QoS (10 );
76
+ qos.reliability (static_cast <rmw_qos_reliability_policy_t >(QOS_POLICY_RELIABILITY_SYSTEM_DEFAULT));
77
+ qos.durability (static_cast <rmw_qos_durability_policy_t >(QOS_POLICY_DURABILITY_SYSTEM_DEFAULT));
78
+ qos.history (static_cast <rmw_qos_history_policy_t >(QOS_POLICY_HISTORY_SYSTEM_DEFAULT));
79
+ auto subscriber = node->create_subscription <sensor_msgs::msg::LaserScan>(
80
+ TOPIC_NAME, qos, [&](const sensor_msgs::msg::LaserScan::ConstSharedPtr msg) {
81
+ EXPECT_EQ (msg->header .frame_id , FRAME_ID);
82
+ EXPECT_NE (msg->header .stamp .sec + msg->header .stamp .nanosec , 0 );
83
+
84
+ EXPECT_NEAR (msg->angle_min , START_ANGLE, EPSILON_F);
85
+ EXPECT_NEAR (msg->angle_max , START_ANGLE + (POINT_COUNT - 1 ) * ANGLE_INCREMENT, EPSILON_F);
86
+ EXPECT_NEAR (msg->range_min , *minRange, EPSILON_F);
87
+ EXPECT_NEAR (msg->range_max , *maxRange, EPSILON_F);
88
+ EXPECT_NEAR (msg->angle_increment , ANGLE_INCREMENT, EPSILON_F);
89
+ EXPECT_NEAR (msg->time_increment , TIME_INCREMENT, EPSILON_F);
90
+ EXPECT_NEAR (msg->scan_time , expectedScanTime, EPSILON_F);
91
+
92
+ ASSERT_EQ (msg->ranges .size (), POINT_COUNT);
93
+ ASSERT_EQ (msg->intensities .size (), POINT_COUNT);
94
+ for (int i = 0 ; i < POINT_COUNT; ++i) {
95
+ EXPECT_NEAR (msg->ranges [i], expectedRanges[i], EPSILON_F);
96
+ EXPECT_NEAR (msg->intensities [i], expectedIntensities[i], EPSILON_F);
97
+ }
98
+ ++messageCount;
99
+ });
100
+
101
+ // Run
102
+ for (int i = 0 ; i < MESSAGE_REPEATS; ++i) {
103
+ ASSERT_RGL_SUCCESS (rgl_graph_run (inputNode));
104
+ }
105
+
106
+ // Wait for messages
107
+ {
108
+ auto start = std::chrono::steady_clock::now ();
109
+ do {
110
+ rclcpp::spin_some (node);
111
+ std::this_thread::sleep_for (std::chrono::milliseconds (10 ));
112
+ } while (messageCount != MESSAGE_REPEATS &&
113
+ std::chrono::steady_clock::now () - start < std::chrono::seconds (WAIT_TIME_SECS));
114
+ ASSERT_EQ (messageCount, MESSAGE_REPEATS);
115
+ }
116
+ }
0 commit comments