Fixposition SDK 0.0.0-heads/main-0-g75e6614
Collection of c++ libraries and apps for use with Fixposition products on Linux
Loading...
Searching...
No Matches
ros2.hpp
Go to the documentation of this file.
1/**
2 * \verbatim
3 * ___ ___
4 * \ \ / /
5 * \ \/ / Copyright (c) Fixposition AG (www.fixposition.com) and contributors
6 * / /\ \ License: see the LICENSE file
7 * /__/ \__\
8 * \endverbatim
9 *
10 * @file
11 * @brief Fixposition SDK: ROS2 types and utils
12 *
13 * @page FPSDK_COMMON_ROS2 ROS2 types and utils
14 *
15 * **API**: fpsdk_common/ros2.hpp and fpsdk::common::ros2
16 *
17 * This is only available when built in a ROS2 environment.
18 */
19#ifndef __FPSDK_COMMON_ROS2_HPP__
20#define __FPSDK_COMMON_ROS2_HPP__
21#if FPSDK_USE_ROS2 || defined(_DOXYGEN_)
22
23/* LIBC/STL */
24# include <cstdint>
25# include <string>
26
27/* EXTERNAL */
28
29/* ROS2 */
30# pragma GCC diagnostic push
31// #pragma GCC diagnostic ignored "-Wpedantic"
32// #pragma GCC diagnostic ignored "-Wunused-parameter"
33# pragma GCC diagnostic ignored "-Wshadow"
34# include <rclcpp/rclcpp.hpp>
35//
36# include <rosbag2_cpp/writer.hpp>
37# include <rosbag2_storage/storage_options.hpp>
38//
39# include <nav_msgs/msg/odometry.hpp>
40# include <sensor_msgs/msg/image.hpp>
41# include <sensor_msgs/msg/imu.hpp>
42# include <sensor_msgs/msg/temperature.hpp>
43# include <std_msgs/msg/byte_multi_array.hpp>
44# include <tf2_msgs/msg/tf_message.hpp>
45# pragma GCC diagnostic pop
46
47/* PACKAGE */
48# include "fpsdk_common/ros1.hpp"
49# include "fpsdk_common/time.hpp"
50
51namespace fpsdk {
52namespace common {
53/**
54 * @brief ROS2 types and utils
55 */
56namespace ros2 {
57/* ****************************************************************************************************************** */
58
59/**
60 * @brief Redirect fp:common::logging to ROS console
61 *
62 * This configures the fpsdk::common::logging facility to output via the ROS console. This does *not* configure the ROS
63 * console (logger level, logger name, etc.).
64 *
65 * The mapping of fpsdk::common::logging::LoggingLevel to rclcpp levels is as follows:
66 *
67 * - TRACE and DEBUG --> DEBUG
68 * - INFO and NOTICE --> INFO
69 * - WARNING --> WARN
70 * - ERROR --> ERROR
71 * - FATAL --> FATAL
72 *
73 * @param[in] logger_name The name of the logger. The recommended value is node->get_logger().get_name()
74 */
75void RedirectLoggingToRosConsole(const char* logger_name = "fpsdk_common");
76
77/**
78 * @brief Convert to ROS time (atomic -> POSIX)
79 *
80 * @param[in] time The Time object (atomic)
81 * @param[in] clock_type The clock to use (to assume)
82 *
83 * @returns the ROS time object (POSIX)
84 */
85rclcpp::Time ConvTime(const fpsdk::common::time::Time& time, rcl_clock_type_t clock_type = RCL_ROS_TIME);
86
87/**
88 * @brief Convert from ROS time (POSIX -> atomic)
89 *
90 * @param[in] time The ROS time object (POSIX)
91 *
92 * @returns the Time object (atomic)
93 */
95
96/**
97 * @brief ROS2 bag writer helper
98 */
99class BagWriter
100{
101 public:
102 BagWriter();
103 ~BagWriter();
104
105 /**
106 * @brief Open bag for writing
107 *
108 * @param[in] path Path of the bag directory
109 * @param[in] mcap Use mcap instead of sqlite3 format
110 * @param[in] compress Compress bag more (only with mcap = true), 0 = zstd_small, >=1 = zstd_fast,
111 * ignored with mcap = false
112 *
113 * @returns true if bag was sucessfully opened
114 */
115 bool Open(const std::string& path, const bool mcap = false, const int compress = 0);
116
117 /**
118 * @brief Close bag
119 */
120 void Close();
121
122 /**
123 * @brief Write a message to the bag
124 *
125 * @tparam T ROS message type
126 * @param[in] msg The message
127 * @param[in] topic Topic name
128 * @param[in] time Bag record time
129 *
130 * @returns true if message was added, false otherwise (message definition missing)
131 */
132 template <typename T>
133 bool WriteMessage(const T& msg, const std::string& topic, const rclcpp::Time& time)
134 {
135 bool ok = false;
136 try {
137 if (bag_) {
138 bag_->write(msg, topic, time);
139 ok = true;
140 }
141 } catch (const std::exception& ex) {
142 WARNING("BagWriter: write fail: %s", ex.what());
143 }
144 return ok;
145 }
146
147 /**
148 * @brief Write a message to the bag
149 *
150 * @tparam T ROS message type
151 * @param[in] msg The message
152 * @param[in] topic Topic name
153 * @param[in] time Bag record time
154 */
155 template <typename T>
156 bool WriteMessage(const T& msg, const std::string& topic, const common::time::RosTime& time)
157 {
158 return WriteMessage(msg, topic, rclcpp::Time(time.sec_, time.nsec_, RCL_ROS_TIME));
159 }
160
161 /**
162 * @brief Add ROS message definition from .fpl
163 *
164 * @note No checks on the provided data are done!
165 *
166 * @param[in] rosmsgdef The message definition
167 */
168 void AddMsgDef(const common::fpl::RosMsgDef& rosmsgdef);
169
170 /**
171 * @brief Write message from .fpl
172 *
173 * @note No checks on the provided data are done!
174 *
175 * @param[in] rosmsgbin The recorded message
176 *
177 * @returns true if message was added, false otherwise (e.g. ROS1->ROS2 conversion not implemented)
178 */
179 bool WriteMessage(const common::fpl::RosMsgBin& rosmsgbin);
180
181 private:
182 std::unique_ptr<rosbag2_cpp::Writer> bag_; //!< Bag file handle
183 std::map<std::string, common::fpl::RosMsgDef> defs_; //!< Message definitions (connection headers)
184};
185# ifdef _DOXYGEN_
186
187// Dummy documentation
188/**
189 * @brief Convert ROS1 message to ROS2 message
190 *
191 * Several conversions in this form are implemented. See the source code for details.
192 *
193 * @tparam Ros1MsgT ROS1 message type
194 * @tparam Ros2MsgT ROS2 message type
195 * @param[in] ros1 ROS1 message
196 * @param[out] ros2 ROS2 message
197 */
198template <typename Ros1MsgT, typename Ros2MsgT>
199void Ros1ToRos2(Ros1MsgT& ros1, Ros2MsgT& ros2);
200
201# else
202
203inline void Ros1ToRos2(const ros::Time& ros1, builtin_interfaces::msg::Time& ros2)
204{
205 ros2.sec = ros1.sec;
206 ros2.nanosec = ros1.nsec;
207}
208
209// ---------------------------------------------------------------------------------------------------------------------
210
211inline void Ros1ToRos2(const boost::array<double, 9>& ros1, std::array<double, 9>& ros2)
212{
213 for (std::size_t ix = 0; ix < 9; ix++) {
214 ros2[ix] = ros1[ix];
215 }
216}
217
218inline void Ros1ToRos2(const boost::array<double, 36>& ros1, std::array<double, 36>& ros2)
219{
220 for (std::size_t ix = 0; ix < 36; ix++) {
221 ros2[ix] = ros1[ix];
222 }
223}
224
225// ---------------------------------------------------------------------------------------------------------------------
226
227inline void Ros1ToRos2(const std_msgs::Header& ros1, std_msgs::msg::Header& ros2)
228{
229 ros2.frame_id = ros1.frame_id;
230 Ros1ToRos2(ros1.stamp, ros2.stamp);
231}
232
233// ---------------------------------------------------------------------------------------------------------------------
234
235inline void Ros1ToRos2(const geometry_msgs::Quaternion& ros1, geometry_msgs::msg::Quaternion& ros2)
236{
237 ros2.x = ros1.x;
238 ros2.y = ros1.y;
239 ros2.z = ros1.z;
240 ros2.w = ros1.w;
241}
242
243inline void Ros1ToRos2(const geometry_msgs::Vector3& ros1, geometry_msgs::msg::Vector3& ros2)
244{
245 ros2.x = ros1.x;
246 ros2.y = ros1.y;
247 ros2.z = ros1.z;
248}
249
250inline void Ros1ToRos2(const geometry_msgs::Point& ros1, geometry_msgs::msg::Point& ros2)
251{
252 ros2.x = ros1.x;
253 ros2.y = ros1.y;
254 ros2.z = ros1.z;
255}
256
257inline void Ros1ToRos2(const geometry_msgs::Pose& ros1, geometry_msgs::msg::Pose& ros2)
258{
259 Ros1ToRos2(ros1.position, ros2.position);
260 Ros1ToRos2(ros1.orientation, ros2.orientation);
261}
262
263inline void Ros1ToRos2(const geometry_msgs::Twist& ros1, geometry_msgs::msg::Twist& ros2)
264{
265 Ros1ToRos2(ros1.linear, ros2.linear);
266 Ros1ToRos2(ros1.angular, ros2.angular);
267}
268
269inline void Ros1ToRos2(const geometry_msgs::PoseWithCovariance& ros1, geometry_msgs::msg::PoseWithCovariance& ros2)
270{
271 Ros1ToRos2(ros1.pose, ros2.pose);
272 Ros1ToRos2(ros1.covariance, ros2.covariance);
273}
274
275inline void Ros1ToRos2(const geometry_msgs::TwistWithCovariance& ros1, geometry_msgs::msg::TwistWithCovariance& ros2)
276{
277 Ros1ToRos2(ros1.twist, ros2.twist);
278 Ros1ToRos2(ros1.covariance, ros2.covariance);
279}
280
281inline void Ros1ToRos2(const geometry_msgs::Transform& ros1, geometry_msgs::msg::Transform& ros2)
282{
283 Ros1ToRos2(ros1.translation, ros2.translation);
284 Ros1ToRos2(ros1.rotation, ros2.rotation);
285}
286
287inline void Ros1ToRos2(const geometry_msgs::TransformStamped& ros1, geometry_msgs::msg::TransformStamped& ros2)
288{
289 Ros1ToRos2(ros1.header, ros2.header);
290 ros2.child_frame_id = ros1.child_frame_id;
291 Ros1ToRos2(ros1.transform, ros2.transform);
292}
293
294// ---------------------------------------------------------------------------------------------------------------------
295
296inline void Ros1ToRos2(const sensor_msgs::Imu& ros1, sensor_msgs::msg::Imu& ros2)
297{
298 Ros1ToRos2(ros1.header, ros2.header);
299 Ros1ToRos2(ros1.orientation, ros2.orientation);
300 Ros1ToRos2(ros1.orientation_covariance, ros2.orientation_covariance);
301 Ros1ToRos2(ros1.angular_velocity, ros2.angular_velocity);
302 Ros1ToRos2(ros1.angular_velocity_covariance, ros2.angular_velocity_covariance);
303 Ros1ToRos2(ros1.linear_acceleration, ros2.linear_acceleration);
304 Ros1ToRos2(ros1.linear_acceleration_covariance, ros2.linear_acceleration_covariance);
305}
306
307inline void Ros1ToRos2(const sensor_msgs::Temperature& ros1, sensor_msgs::msg::Temperature& ros2)
308{
309 Ros1ToRos2(ros1.header, ros2.header);
310 ros2.temperature = ros1.temperature;
311 ros2.variance = ros1.variance;
312}
313
314inline void Ros1ToRos2(const sensor_msgs::Image& ros1, sensor_msgs::msg::Image& ros2)
315{
316 Ros1ToRos2(ros1.header, ros2.header);
317 ros2.height = ros1.height;
318 ros2.width = ros1.width;
319 ros2.encoding = ros1.encoding;
320 ros2.step = ros1.step;
321 ros2.data = ros1.data;
322}
323
324// ---------------------------------------------------------------------------------------------------------------------
325
326inline void Ros1ToRos2(const nav_msgs::Odometry& ros1, nav_msgs::msg::Odometry& ros2)
327{
328 Ros1ToRos2(ros1.header, ros2.header);
329 ros2.child_frame_id = ros1.child_frame_id;
330 Ros1ToRos2(ros1.pose, ros2.pose);
331 Ros1ToRos2(ros1.twist, ros2.twist);
332}
333
334// ---------------------------------------------------------------------------------------------------------------------
335
336inline void Ros1ToRos2(const tf2_msgs::TFMessage& ros1, tf2_msgs::msg::TFMessage& ros2)
337{
338 for (auto& tf_ros1 : ros1.transforms) {
339 geometry_msgs::msg::TransformStamped tf_ros2;
340 Ros1ToRos2(tf_ros1, tf_ros2);
341 ros2.transforms.push_back(std::move(tf_ros2));
342 }
343}
344
345# endif // !_DOXYGEN_
346
347/* ****************************************************************************************************************** */
348} // namespace ros2
349} // namespace common
350} // namespace fpsdk
351#endif // FPSDK_USE_ROS2 || _DOXYGEN_
352#endif // __FPSDK_COMMON_ROS2_HPP__
bool Open(const std::string &path, const bool mcap=false, const int compress=0)
Open bag for writing.
void AddMsgDef(const common::fpl::RosMsgDef &rosmsgdef)
Add ROS message definition from .fpl.
bool WriteMessage(const T &msg, const std::string &topic, const rclcpp::Time &time)
Write a message to the bag.
Definition ros2.hpp:133
bool WriteMessage(const T &msg, const std::string &topic, const common::time::RosTime &time)
Write a message to the bag.
Definition ros2.hpp:156
bool WriteMessage(const common::fpl::RosMsgBin &rosmsgbin)
Write message from .fpl.
#define WARNING(...)
Print a warning message.
Definition logging.hpp:81
File and path utilities.
Definition path.hpp:38
ROS1 types and utils.
Definition ros1.hpp:65
ROS2 types and utils.
Definition ros2.hpp:56
void RedirectLoggingToRosConsole(const char *logger_name="fpsdk_common")
Redirect fp:common::logging to ROS console.
rclcpp::Time ConvTime(const fpsdk::common::time::Time &time, rcl_clock_type_t clock_type=RCL_ROS_TIME)
Convert to ROS time (atomic -> POSIX).
void Ros1ToRos2(Ros1MsgT &ros1, Ros2MsgT &ros2)
Convert ROS1 message to ROS2 message.
Time utilities.
Definition time.hpp:39
Fixposition SDK: Common library.
Definition doc.hpp:21
Fixposition SDK.
Fixposition SDK: ROS1 types and utils.
Helper for extracting a serialised ROS message.
Definition fpl.hpp:361
Helper for extracting ROS message definition (the relevant fields from the "connection header").
Definition fpl.hpp:338
Minimal ros::Time() / rplcpp::Time implementation (that doesn't throw).
Definition time.hpp:156
Fixposition SDK: Time utilities.