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
ros1.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: ROS1 types and utils
12 *
13 * @page FPSDK_COMMON_ROS1 ROS1 types and utils
14 *
15 * **API**: fpsdk_common/ros1.hpp and fpsdk::common::ros1
16 *
17 * @note Some of this always available, even when built in a non-ROS or ROS2 environment, some of it is only available
18 * when built in a ROS1 environment, see @ref FPSDK_BUILD_DEPS.
19 */
20#ifndef __FPSDK_COMMON_ROS1_HPP__
21#define __FPSDK_COMMON_ROS1_HPP__
22
23/* LIBC/STL */
24#include <cstdint>
25#include <map>
26#include <memory>
27#include <string>
28#include <vector>
29
30/* EXTERNAL */
31#include <nlohmann/json.hpp>
32
33/* ROS1 from fpsdk_common/rosnoros or real ROS1 */
34#pragma GCC diagnostic push
35#pragma GCC diagnostic ignored "-Wpedantic"
36#pragma GCC diagnostic ignored "-Wunused-parameter"
37#pragma GCC diagnostic ignored "-Wshadow"
38#pragma GCC diagnostic ignored "-Wunused-function"
39//
40#if FPSDK_USE_ROS1
41# include <ros/console.h>
42# include <ros/time.h>
43#endif
44//
45#include <nav_msgs/Odometry.h>
46#include <sensor_msgs/Image.h>
47#include <sensor_msgs/Imu.h>
48#include <sensor_msgs/Temperature.h>
49#include <std_msgs/ByteMultiArray.h>
50#include <tf2_msgs/TFMessage.h>
51//
52#include <ros/serialization.h>
53//
54#pragma GCC diagnostic pop
55
56/* PACKAGE */
57#include "fpl.hpp"
58#include "time.hpp"
59
60namespace fpsdk {
61namespace common {
62/**
63 * @brief ROS1 types and utils
64 */
65namespace ros1 {
66/* ****************************************************************************************************************** */
67
68#ifndef _DOXYGEN_
69// Helper for ros de-serialization. We could DeserializeMessage() using ros::serialization::deserialize(IStream(buf),
70// msg). However, the IStream() wants a mutable buffer, which is not nice. ConstBuffer() provides the Stream() interface
71// without needing the mutability of the buffer itself.
72struct ConstBuffer
73{
74 ConstBuffer(const std::vector<uint8_t>& buf)
75 : data_{ buf.data() }, end_{ buf.data() + static_cast<uint32_t>(buf.size()) }
76 {
77 }
78 ConstBuffer(const uint8_t* data, size_t size) : data_(data), end_(data + static_cast<uint32_t>(size))
79 {
80 }
81
82 static const ros::serialization::StreamType stream_type = ros::serialization::stream_types::Input;
83 inline const uint8_t* getData()
84 {
85 return data_;
86 }
87 inline const uint8_t* advance(uint32_t len)
88 {
89 const uint8_t* old_data = data_;
90 data_ += len;
91 if (data_ > end_) {
92 ros::serialization::throwStreamOverrun();
93 }
94 return old_data;
95 }
96 inline uint32_t getLength()
97 {
98 return static_cast<uint32_t>(end_ - data_);
99 }
100
101 template <typename T>
102 inline void next(T& t)
103 {
104 ros::serialization::deserialize(*this, t);
105 }
106
107 template <typename T>
108 inline ConstBuffer& operator>>(T& t)
109 {
110 ros::serialization::deserialize(*this, t);
111 return *this;
112 }
113
114 private:
115 const uint8_t* data_;
116 const uint8_t* end_;
117};
118#endif // _DOXYGEN_
119
120/**
121 * @brief Deserialise ROS1 message
122 *
123 * @tparam RosMsgT The ROS1 message type
124 * @param[in] buf The serialised ROS message
125 * @param[out] msg The deserialised ROS message
126 */
127template <typename RosMsgT>
128inline void DeserializeMessage(const std::vector<uint8_t>& buf, RosMsgT& msg)
129{
130#if FPSDK_USE_ROS1
131 ros::serialization::IStream s((uint8_t*)buf.data(), static_cast<uint32_t>(buf.size())); // :-(
132 ros::serialization::deserialize(s, msg);
133#else
134 ConstBuffer m(buf);
135 ros::serialization::Serializer<RosMsgT>::read(m, msg);
136#endif
137}
138
139/**
140 * @brief Convert to ROS time (atomic -> POSIX)
141 *
142 * @param[in] time The Time object (atomic)
143 *
144 * @returns the ROS time object (POSIX)
145 */
146ros::Time ConvTime(const time::Time& time);
147
148/**
149 * @brief Convert from ROS time (POSIX -> atomic)
150 *
151 * @param[in] time The ROS time object (POSIX)
152 *
153 * @returns the Time object (atomic)
154 */
155time::Time ConvTime(const ros::Time& time);
156
157/**
158 * @brief ROS1 bag (rosbag) writer
159 *
160 * This writes ROS1 bag files (rosbag format version 2.0). Unlike the rosbag library from ROS1 this does not need ROS
161 * and therefore it works in all builds of the SDK (with ROS1, with ROS2, and without any ROS). Messages can either be
162 * given as ROS1 message objects (see WriteMessage()) or as already serialised data from a .fpl logfile (see
163 * AddMsgDef() and WriteMessage()).
164 *
165 * Compared to the original rosbag library this implementation has some limitations:
166 *
167 * - Only "bz2" chunk compression is available (and only if compiled with BZip2, see @ref FPSDK_BUILD_DEPS)
168 * - No encryption
169 * - Only one connection per topic
170 * - Write only (no reading, no appending to existing bags)
171 *
172 * The resulting bags are valid rosbag version 2.0 files and can be read by any ROS1 tool (rosbag info, rosbag play,
173 * rqt_bag, ...) as well as other tools that understand the format.
174 */
175class BagWriter
176{
177 public:
178 BagWriter();
179 ~BagWriter();
180
181 BagWriter(const BagWriter&) = delete; //!< No copy
182 BagWriter& operator=(const BagWriter&) = delete; //!< No copy
183
184 /**
185 * @brief Open bag for writing
186 *
187 * @param[in] path Path/filename of the bag file (an existing file is overwritten)
188 * @param[in] compress Compress bag, 0 = no compression, 1+ = BZ2 (if compiled in)
189 *
190 * @returns true if bag was sucessfully opened, false otherwise (bad path, compression requested but bz2 support not
191 * compiled in, ...)
192 */
193 bool Open(const std::string& path, const int compress = 0);
194
195 /**
196 * @brief Close bag
197 *
198 * @note Failing to close the bag (for example, by not destroying the object) leaves an unusable (unindexed) file
199 * behind. The index is only written on close.
200 */
201 void Close();
202
203 /**
204 * @brief Write a message to the bag
205 *
206 * @tparam T ROS message type
207 * @param[in] msg The message
208 * @param[in] topic Topic name
209 * @param[in] time Bag record time
210 *
211 * @returns true if message was added, false otherwise (bag not open, write error)
212 */
213 template <typename T>
214 bool WriteMessage(const T& msg, const std::string& topic, const time::RosTime& time = {})
215 {
216 const uint32_t size = ros::serialization::serializationLength(msg);
217 std::vector<uint8_t> data(size);
218 if (size > 0) {
219 ros::serialization::OStream stream(data.data(), size);
220 ros::serialization::serialize(stream, msg);
221 }
222 return WriteSerialised(topic, time, ros::message_traits::datatype<T>(), ros::message_traits::md5sum<T>(),
223 ros::message_traits::definition<T>(), data.data(), data.size());
224 }
225
226 /**
227 * @brief Write a message to the bag
228 *
229 * @tparam T ROS message type
230 * @param[in] msg The message
231 * @param[in] topic Topic name
232 * @param[in] time Bag record time
233 *
234 * @returns true if message was added, false otherwise (bag not open, write error)
235 */
236 template <typename T>
237 bool WriteMessage(const T& msg, const std::string& topic, const ros::Time& time)
238 {
239 return WriteMessage<T>(msg, topic, time::RosTime(time.sec, time.nsec));
240 }
241
242 /**
243 * @brief Add ROS message definition from .fpl
244 *
245 * @note No checks on the provided data are done!
246 *
247 * @param[in] rosmsgdef The message definition
248 */
249 void AddMsgDef(const fpl::RosMsgDef& rosmsgdef);
250
251 /**
252 * @brief Write message from .fpl
253 *
254 * @note No checks on the provided data are done!
255 *
256 * @param[in] rosmsgbin The recorded message
257 *
258 * @returns true if message was added, false otherwise (message definition missing, bag not open, write error)
259 */
260 bool WriteMessage(const fpl::RosMsgBin& rosmsgbin);
261
262 private:
263#ifndef _DOXYGEN_
264 struct Impl; // The actual bag file writer, see ros1.cpp
265 std::unique_ptr<Impl> impl_;
266
267 bool WriteSerialised(const std::string& topic, const time::RosTime& time, const std::string& msg_name,
268 const std::string& msg_md5, const std::string& msg_def, const uint8_t* data, const std::size_t size);
269#endif // _DOXYGEN_
270};
271
272#if FPSDK_USE_ROS1 || defined(_DOXYGEN_)
273/**
274 * @brief Redirect fpsdk:common::logging to ROS console
275 *
276 * @note This is only available when built in a ROS1 environment.
277 *
278 * This configures the fpsdk::common::logging facility to output via the ROS console. This does *not* configure the ROS
279 * console (logger level, logger name, etc.).
280 *
281 * The mapping of fpsdk::common::logging::LoggingLevel to ros::console::levels is as follows:
282 *
283 * - TRACE and DEBUG --> DEBUG
284 * - INFO and NOTICE --> INFO
285 * - WARNING --> WARN
286 * - ERROR --> ERROR
287 * - FATAL --> FATAL
288 *
289 * @param[in] logger_name The name of the logger. The default value should give the caller package's
290 * ROSCONSOLE_DEFAULT_NAME, for example, "ros1_fpsdk_demo". That is, typically this argument
291 * should be left empty (the default value).
292 */
293void RedirectLoggingToRosConsole(const char* logger_name = ROSCONSOLE_DEFAULT_NAME /* = caller's package name */);
294#endif
295
296/* ****************************************************************************************************************** */
297} // namespace ros1
298} // namespace common
299} // namespace fpsdk
300#endif // __FPSDK_COMMON_ROS1_HPP__
void AddMsgDef(const fpl::RosMsgDef &rosmsgdef)
Add ROS message definition from .fpl.
BagWriter & operator=(const BagWriter &)=delete
No copy.
bool WriteMessage(const fpl::RosMsgBin &rosmsgbin)
Write message from .fpl.
bool WriteMessage(const T &msg, const std::string &topic, const time::RosTime &time={})
Write a message to the bag.
Definition ros1.hpp:214
BagWriter(const BagWriter &)=delete
No copy.
bool Open(const std::string &path, const int compress=0)
Open bag for writing.
bool WriteMessage(const T &msg, const std::string &topic, const ros::Time &time)
Write a message to the bag.
Definition ros1.hpp:237
Fixposition SDK: .fpl utilities.
File and path utilities.
Definition path.hpp:38
ROS1 types and utils.
Definition ros1.hpp:65
void DeserializeMessage(const std::vector< uint8_t > &buf, RosMsgT &msg)
Deserialise ROS1 message.
Definition ros1.hpp:128
ros::Time ConvTime(const time::Time &time)
Convert to ROS time (atomic -> POSIX).
void RedirectLoggingToRosConsole(const char *logger_name=ROSCONSOLE_DEFAULT_NAME)
Redirect fpsdk:common::logging to ROS console.
Time utilities.
Definition time.hpp:39
Fixposition SDK: Common library.
Definition doc.hpp:21
Fixposition SDK.
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.