ros_parser.cpp
Go to the documentation of this file.
1 #include "ros_parser.h"
3 
4 using namespace PJ;
5 using namespace RosMsgParser;
6 
8 constexpr double RAD_TO_DEG = 180.0 / M_PI;
9 
10 ParserROS::ParserROS(const std::string& topic_name,
11  const std::string& type_name,
12  const std::string& schema,
13  RosMsgParser::Deserializer* deserializer,
15  : MessageParser(topic_name, data)
16  ,_parser(topic_name, type_name, schema)
17  ,_deserializer(deserializer)
18  ,_topic(topic_name)
19 {
20  auto policy = clampLargeArray() ? Parser::KEEP_LARGE_ARRAYS :
21  Parser::DISCARD_LARGE_ARRAYS;
22 
24 
25 
26  _is_diangostic_msg = ( Msg::DiagnosticStatus::id() == type_name);
27  _is_jointstate_msg = ( Msg::JointState::id() == type_name);
28  _is_tf2_msg = ( Msg::TFMessage::id() == type_name);
29 
30  //---------- detect quaternion in schema --------
31  auto hasQuaternion = [this](const auto& node) {
32  if(node->value()->type() == quaternion_type)
33  {
34  _contains_quaternion = true;
35  }
36  };
37  const auto& tree = _parser.getSchema()->field_tree;
38  tree.visit(hasQuaternion, tree.croot());
39 }
40 
41 bool ParserROS::parseMessage(const PJ::MessageRef serialized_msg, double &timestamp)
42 {
43  if( _is_diangostic_msg )
44  {
45  parseDiagnosticMsg(serialized_msg, timestamp);
46  return true;
47  }
48  if( _is_jointstate_msg )
49  {
50  parseJointStateMsg(serialized_msg, timestamp);
51  return true;
52  }
53  if( _is_tf2_msg )
54  {
55  parseTF2Msg(serialized_msg, timestamp);
56  return true;
57  }
58 
59  _parser.deserialize(serialized_msg, &_flat_msg, _deserializer.get());
60 
61  std::string series_name;
62 
63  for(const auto& [key, str]: _flat_msg.name)
64  {
65  key.toStr(series_name);
66  StringSeries& data = getStringSeries(series_name);
67  data.pushBack( {timestamp, str } );
68  }
69 
70  for(const auto& [key, value]: _flat_msg.value)
71  {
72  key.toStr(series_name);
73  PlotData& data = getSeries(series_name);
74  data.pushBack( {timestamp, value.convert<double>() } );
75  }
76 
78  {
79  appendRollPitchYaw(timestamp);
80  }
81  return true;
82 }
83 
84 void ParserROS::setLargeArraysPolicy(bool clamp, unsigned max_size)
85 {
86  auto policy = clamp ? RosMsgParser::Parser::KEEP_LARGE_ARRAYS :
88 
89  _parser.setMaxArrayPolicy( policy, max_size );
90  MessageParser::setLargeArraysPolicy(clamp, max_size);
91 }
92 
94 {
95 
96  for(size_t i=0; i< _flat_msg.value.size(); i++ )
97  {
98  const auto& [key, val] = _flat_msg.value[i];
99 
100  if( key.fields.size() < 2 || (i+3) >= _flat_msg.value.size() )
101  {
102  continue;
103  }
104  size_t last = key.fields.size() - 1;
105 
106  if( key.fields[last-1]->type() == quaternion_type &&
107  key.fields[last]->type().typeID() == RosMsgParser::FLOAT64 &&
108  key.fields[last]->name() == "x")
109  {
110  Msg::Quaternion quat;
111 
112  quat.x = val.convert<double>();
113  quat.y = _flat_msg.value[i+1].second.convert<double>();
114  quat.z = _flat_msg.value[i+2].second.convert<double>();
115  quat.w = _flat_msg.value[i+3].second.convert<double>();
116 
117  std::string prefix = key.toStdString();
118  prefix.pop_back();
119 
120  auto rpy = Msg::QuaternionToRPY( quat );
121 
122  getSeries(prefix + "roll_deg").pushBack( {stamp, RAD_TO_DEG * rpy.roll } );
123  getSeries(prefix + "pitch_deg").pushBack( {stamp, RAD_TO_DEG * rpy.pitch } );
124  getSeries(prefix + "yaw_deg").pushBack( {stamp, RAD_TO_DEG * rpy.yaw } );
125 
126  break;
127  }
128  }
129 }
130 
132 {
133  // only ROS1 as the files header.seq
134  if( dynamic_cast<ROS_Deserializer*>(_deserializer.get()) )
135  {
136  header.seq = _deserializer->deserializeUInt32();
137  }
138 
139  header.stamp.sec = _deserializer->deserializeUInt32();
140  header.stamp.nanosec = _deserializer->deserializeUInt32();
141  _deserializer->deserializeString(header.frame_id);
142 }
143 
144 void ParserROS::parseDiagnosticMsg(const PJ::MessageRef msg_buffer, double &timestamp)
145 {
146  using namespace RosMsgParser;
147 
148  thread_local Msg::DiagnosticArray msg;
149  _deserializer->init( Span<const uint8_t>(msg_buffer.data(), msg_buffer.size()) );
150 
151  parseHeader(msg.header);
152 
153  size_t status_count = _deserializer->deserializeUInt32();
154  msg.status.resize( status_count );
155  for(size_t st = 0; st < status_count; st++)
156  {
157  auto& status = msg.status[st];
158  status.level = _deserializer->deserialize(BYTE).convert<uint8_t>();
159  _deserializer->deserializeString(status.name);
160  _deserializer->deserializeString(status.message);
161  _deserializer->deserializeString(status.hardware_id);
162 
163  status.key_value.clear();
164 
165  size_t key_value_count = _deserializer->deserializeUInt32();
166  std::string key;
167  std::string value_str;
168  for(size_t kv = 0; kv < key_value_count; kv++)
169  {
170  _deserializer->deserializeString(key);
171  _deserializer->deserializeString(value_str);
172  status.key_value.push_back( {key, value_str} );
173  }
174  }
175 
176  //------ Now create the series --------
177  double ts = timestamp;
178  getSeries(fmt::format("{}/header/seq", _topic)).pushBack( {ts, double(msg.header.seq)} );
179  getSeries(fmt::format("{}/header/stamp", _topic)).pushBack( {ts, msg.header.stamp.toSec()} );
180  getStringSeries(fmt::format("{}/header/frame_id", _topic)).pushBack( {ts, msg.header.frame_id} );
181 
182  std::string series_name;
183 
184  for (const auto& status : msg.status)
185  {
186  for (const auto& kv : status.key_value)
187  {
188  if (status.hardware_id.empty())
189  {
190  series_name = fmt::format("{}/{}/{}",
191  _topic, status.name, kv.first);
192  }
193  else {
194  series_name = fmt::format("{}/{}/{}/{}",
195  _topic, status.hardware_id, status.name, kv.first);
196  }
197 
198  bool ok;
199  double value = QString::fromStdString(kv.second).toDouble(&ok);
200 
201  if (ok)
202  {
203  getSeries(series_name).pushBack({ timestamp, value });
204  }
205  else {
206  getStringSeries(series_name).pushBack({ timestamp, kv.second });
207  }
208  }
209  }
210 }
211 
212 void ParserROS::parseJointStateMsg(const MessageRef msg_buffer, double &timestamp)
213 {
214  thread_local Msg::JointState msg;
215  _deserializer->init( Span<const uint8_t>(msg_buffer.data(), msg_buffer.size()) );
216 
217  msg.name.clear();
218  msg.position.clear();
219  msg.velocity.clear();
220  msg.effort.clear();
221 
222  parseHeader(msg.header);
223 
224  size_t name_size = _deserializer->deserializeUInt32();
225  if( name_size > 0 )
226  {
227  msg.name.resize( name_size );
228  for(auto& name: msg.name)
229  {
230  _deserializer->deserializeString(name);
231  }
232  }
233 
234  //-----------
235  size_t pos_size = _deserializer->deserializeUInt32();
236  if( pos_size > 0 )
237  {
238  msg.position.resize( pos_size );
239  for(auto& pos: msg.position)
240  {
241  pos = _deserializer->deserialize(FLOAT64).convert<double>();
242  }
243  }
244  //-----------
245  size_t vel_size = _deserializer->deserializeUInt32();
246  if( vel_size > 0 )
247  {
248  msg.velocity.resize( vel_size );
249  for(auto& vel: msg.velocity)
250  {
251  vel = _deserializer->deserialize(FLOAT64).convert<double>();
252  }
253  }
254  //-----------
255  size_t eff_size = _deserializer->deserializeUInt32();
256  if( eff_size > 0 )
257  {
258  msg.effort.resize( eff_size );
259  for(auto& eff: msg.effort)
260  {
261  eff = _deserializer->deserialize(FLOAT64).convert<double>();
262  }
263  }
264  //---------------------------
265  std::string series_name;
266  for(size_t i=0; i < std::max(name_size, pos_size); i++)
267  {
268  series_name = fmt::format("{}/{}/position", _topic, msg.name[i]);
269  getSeries(series_name).pushBack({ timestamp, msg.position[i] });
270  }
271  for(size_t i=0; i < std::max(name_size, vel_size); i++)
272  {
273  series_name = fmt::format("{}/{}/velocity", _topic, msg.name[i]);
274  getSeries(series_name).pushBack({ timestamp, msg.velocity[i] });
275  }
276  for(size_t i=0; i < std::max(name_size, eff_size); i++)
277  {
278  series_name = fmt::format("{}/{}/effort", _topic, msg.name[i]);
279  getSeries(series_name).pushBack({ timestamp, msg.effort[i] });
280  }
281 }
282 
283 void ParserROS::parseTF2Msg(const MessageRef msg_buffer, double &stamp)
284 {
285  thread_local Msg::TFMessage msg;
286  _deserializer->init( Span<const uint8_t>(msg_buffer.data(), msg_buffer.size()) );
287 
288  size_t transform_size = _deserializer->deserializeUInt32();
289 
290  if( transform_size == 0)
291  {
292  return;
293  }
294  msg.transforms.resize(transform_size);
295 
296  auto getDouble = [this]() {
297  return _deserializer->deserialize(FLOAT64).convert<double>();
298  };
299 
300  for(auto& trans: msg.transforms)
301  {
302  parseHeader(trans.header);
303  _deserializer->deserializeString(trans.child_frame_id);
304 
305  std::string prefix;
306  if (trans.header.frame_id.empty())
307  {
308  prefix = fmt::format("{}/{}",
309  _topic_name, trans.child_frame_id);
310  }
311  else {
312  prefix = fmt::format("{}/{}/{}",
313  _topic_name, trans.header.frame_id, trans.child_frame_id);
314  }
315 
316  getSeries(fmt::format("{}/translation/x", prefix)).pushBack( {stamp, getDouble()} );
317  getSeries(fmt::format("{}/translation/y", prefix)).pushBack( {stamp, getDouble()} );
318  getSeries(fmt::format("{}/translation/z", prefix)).pushBack( {stamp, getDouble()} );
319 
320  Msg::Quaternion quat = { getDouble(), getDouble(), getDouble(), getDouble() };
321  auto RPY = Msg::QuaternionToRPY(quat);
322 
323  getSeries(fmt::format("{}/rotation/x", prefix)).pushBack( {stamp, quat.x} );
324  getSeries(fmt::format("{}/rotation/y", prefix)).pushBack( {stamp, quat.y} );
325  getSeries(fmt::format("{}/rotation/z", prefix)).pushBack( {stamp, quat.z} );
326  getSeries(fmt::format("{}/rotation/w", prefix)).pushBack( {stamp, quat.w} );
327 
328  getSeries(fmt::format("{}/rotation/roll_deg", prefix)).pushBack(
329  {stamp, RPY.roll * RAD_TO_DEG} );
330  getSeries(fmt::format("{}/rotation/pitch_deg", prefix)).pushBack(
331  {stamp, RPY.roll * RAD_TO_DEG} );
332  getSeries(fmt::format("{}/rotation/yaw_deg", prefix)).pushBack(
333  {stamp, RPY.yaw * RAD_TO_DEG} );
334  }
335 
336 }
static const char * id()
std::vector< std::pair< FieldsVector, std::string > > name
List of all those parsed fields that can be represented by a "string".
Definition: ros_parser.hpp:41
std::shared_ptr< RosMsgParser::Deserializer > _deserializer
Definition: ros_parser.h:23
void parseHeader(PJ::Msg::Header &header)
Definition: ros_parser.cpp:131
unsigned maxArraySize() const
PJ::Msg::Time stamp
size_t size() const
RPY QuaternionToRPY(Quaternion q)
bool deserialize(Span< const uint8_t > buffer, FlatMessage *flat_output, Deserializer *deserializer) const
deserializeIntoFlatContainer takes a raw buffer of memory and extract information from it...
bool _contains_quaternion
Definition: ros_parser.h:37
ParserROS(const std::string &topic_name, const std::string &type_name, const std::string &schema, RosMsgParser::Deserializer *deserializer, PJ::PlotDataMapRef &data)
Definition: ros_parser.cpp:10
bool _is_diangostic_msg
Definition: ros_parser.h:38
unsigned char BYTE
Definition: lz4.c:286
std::string _topic
Definition: ros_parser.h:25
void parseJointStateMsg(const PJ::MessageRef serialized_msg, double &timestamp)
Definition: ros_parser.cpp:212
Definition: lz4.c:1706
void appendRollPitchYaw(double timestamp)
Definition: ros_parser.cpp:93
bool parseMessage(const PJ::MessageRef serialized_msg, double &timestamp) override
Definition: ros_parser.cpp:41
RosMsgParser::FlatMessage _flat_msg
Definition: ros_parser.h:24
const std::shared_ptr< MessageSchema > & getSchema() const
getSchema provides some metadata amout a registered ROSMessage.
bool clampLargeArray() const
std::string type_name(lua_State *L, type t)
Definition: sol.hpp:8079
std::string frame_id
void pushBack(const Point &p) override
Definition: stringseries.h:39
bool _is_jointstate_msg
Definition: ros_parser.h:39
RosMsgParser::Parser _parser
Definition: ros_parser.h:22
constexpr double RAD_TO_DEG
Definition: ros_parser.cpp:8
#define M_PI
Definition: qwt_math.h:56
void pushBack(const Point &p) override
Definition: timeseries.h:61
void setMaxArrayPolicy(MaxArrayPolicy discard_entire_array, size_t max_array_size)
Definition: ros_parser.hpp:74
bool _is_tf2_msg
Definition: ros_parser.h:40
const uint8_t * data() const
The MessageParser is the base class used to parse a message with a specific encoding+schema.
Definition: core.h:1131
PlotData & getSeries(const std::string &key)
void parseDiagnosticMsg(const PJ::MessageRef serialized_msg, double &timestamp)
Definition: ros_parser.cpp:144
static ROSType quaternion_type(Msg::Quaternion::id())
void setLargeArraysPolicy(bool clamp, unsigned max_size) override
Definition: ros_parser.cpp:84
StringSeries & getStringSeries(const std::string &key)
std::vector< std::pair< FieldsVector, Variant > > value
Definition: ros_parser.hpp:38
Definition: format.h:895
std::basic_string< Char > format(const text_style &ts, const S &format_str, const Args &... args)
Definition: color.h:583
void parseTF2Msg(const PJ::MessageRef serialized_msg, double &timestamp)
Definition: ros_parser.cpp:283


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Jun 19 2023 03:01:39