16 #ifndef PSEN_SCAN_V2_ROS_SCANNER_NODE_H
17 #define PSEN_SCAN_V2_ROS_SCANNER_NODE_H
26 #include <fmt/format.h>
28 #include <gtest/gtest_prod.h>
31 #include <std_msgs/UInt8.h>
32 #include <sensor_msgs/LaserScan.h>
48 using namespace std::chrono_literals;
54 template <
typename S = ScannerV2>
68 const std::string& topic,
69 const std::string& tf_prefix,
70 const double& x_axis_rotation,
83 void publishChangedIOStates(
const std::vector<psen_scan_v2_standalone::IOState>& io_states);
88 std::unordered_map<ScannerId, ros::Publisher>
pubs_scan_;
94 std::atomic_bool terminate_{
false };
98 friend class RosScannerNodeTests;
99 FRIEND_TEST(RosScannerNodeTests, shouldStartAndStopSuccessfullyIfScannerRespondsToRequests);
100 FRIEND_TEST(RosScannerNodeTests, shouldPublishScansWhenLaserScanCallbackIsInvoked);
101 FRIEND_TEST(RosScannerNodeTests, shouldPublishActiveZonesetWhenLaserScanCallbackIsInvoked);
102 FRIEND_TEST(RosScannerNodeTests, shouldWaitWhenStopRequestResponseIsMissing);
103 FRIEND_TEST(RosScannerNodeTests, shouldProvideScanTopic);
104 FRIEND_TEST(RosScannerNodeTests, shouldProvideActiveZonesetTopic);
105 FRIEND_TEST(RosScannerNodeTests, shouldPublishScanEqualToConversionOfSuppliedLaserScan);
106 FRIEND_TEST(RosScannerNodeTests, shouldThrowExceptionSetInScannerStartFuture);
107 FRIEND_TEST(RosScannerNodeTests, shouldThrowExceptionSetInScannerStopFuture);
108 FRIEND_TEST(RosScannerNodeTests, shouldPublishChangedIOStatesEqualToConversionOfSuppliedStandaloneIOStates);
109 FRIEND_TEST(RosScannerNodeTests, shouldPublishLatchedOnIOStatesTopic);
110 FRIEND_TEST(RosScannerNodeTests, shouldLogChangedIOStates);
115 template <
typename S>
117 const std::string& topic,
118 const std::string& tf_prefix,
119 const double& x_axis_rotation,
122 , x_axis_rotation_(x_axis_rotation)
126 tf_prefixes_.insert(std::make_pair(ScannerId::master, tf_prefix));
132 std::string tf_prefix_subscriber =
134 tf_prefixes_.insert(std::make_pair(
id, tf_prefix_subscriber));
140 template <
typename S>
145 std::string tf_prefix_with_subscriber = tf_prefixes_.at(scan.
scannerId());
146 const auto laser_scan_msg =
toLaserScanMsg(scan, tf_prefix_with_subscriber, x_axis_rotation_);
149 "Publishing laser scan with angle_min={:.1f} angle_max={:.1f} angle_increment={:.1f} degrees. {} angle values.",
153 laser_scan_msg.ranges.size());
154 pubs_scan_.at(scan.
scannerId()).publish(laser_scan_msg);
156 std_msgs::UInt8 active_zoneset;
158 pub_zone_.publish(active_zoneset);
160 publishChangedIOStates(scan.
ioStates());
163 catch (
const std::invalid_argument&
e)
170 template <
typename S>
173 std::string tf_prefix_with_subscriber = tf_prefixes_.at(ScannerId::master);
174 for (
const auto& io : io_states)
176 if (last_io_state_ != io)
178 pub_io_.publish(
toIOStateMsg(io, tf_prefix_with_subscriber));
181 "IOs changed, new input: {}, new output: {}",
189 template <
typename S>
195 template <
typename S>
199 auto start_future = scanner_.start();
200 const auto start_status = start_future.wait_for(3
s);
201 if (start_status == std::future_status::ready)
206 while (
ros::ok() && !terminate_)
210 auto stop_future = scanner_.stop();
212 const auto stop_status = stop_future.wait_for(3
s);
213 if (stop_status == std::future_status::ready)
221 #endif // PSEN_SCAN_V2_ROS_SCANNER_NODE_H