ros1_parsers/quaternion_msg.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <geometry_msgs/Quaternion.h>
4 #include "ros1_parser.h"
5 
6 class QuaternionMsgParser : public BuiltinMessageParser<geometry_msgs::Quaternion>
7 {
8 public:
9  QuaternionMsgParser(const std::string& topic_name, PJ::PlotDataMapRef& plot_data)
10  : BuiltinMessageParser<geometry_msgs::Quaternion>(topic_name, plot_data),
11  _pitch_offset(0.0),
12  _roll_offset(0.0),
13  _yaw_offset(0.0),
14  _prev_pitch(0.0),
15  _prev_roll(0.0),
16  _prev_yaw(0.0)
17  {
18  }
19 
20  void parseMessageImpl(const geometry_msgs::Quaternion& msg, double& timestamp) override
21  {
22  if( !_initialized )
23  {
24  _initialized = true;
25  _data.push_back(&getSeries(_topic_name + "/x"));
26  _data.push_back(&getSeries(_topic_name + "/y"));
27  _data.push_back(&getSeries(_topic_name + "/z"));
28  _data.push_back(&getSeries(_topic_name + "/w"));
29 
30  _data.push_back(&getSeries(_topic_name + "/roll_deg"));
31  _data.push_back(&getSeries(_topic_name + "/pitch_deg"));
32  _data.push_back(&getSeries(_topic_name + "/yaw_deg"));
33  }
34 
35  _data[0]->pushBack({ timestamp, msg.x });
36  _data[1]->pushBack({ timestamp, msg.y });
37  _data[2]->pushBack({ timestamp, msg.z });
38  _data[3]->pushBack({ timestamp, msg.w });
39 
40  //-----------------------------
41  auto q = msg;
42  double quat_norm2 = (q.w * q.w) + (q.x * q.x) + (q.y * q.y) + (q.z * q.z);
43  if (std::abs(quat_norm2 - 1.0) > std::numeric_limits<double>::epsilon())
44  {
45  double mult = 1.0 / std::sqrt(quat_norm2);
46  q.x *= mult;
47  q.y *= mult;
48  q.z *= mult;
49  q.w *= mult;
50  }
51 
52  double roll, pitch, yaw;
53  // roll (x-axis rotation)
54  double sinr_cosp = 2 * (q.w * q.x + q.y * q.z);
55  double cosr_cosp = 1 - 2 * (q.x * q.x + q.y * q.y);
56  roll = std::atan2(sinr_cosp, cosr_cosp);
57 
58  // pitch (y-axis rotation)
59  double sinp = 2 * (q.w * q.y - q.z * q.x);
60  if (std::abs(sinp) >= 1)
61  {
62  pitch = std::copysign(M_PI_2, sinp); // use 90 degrees if out of range
63  }
64  else
65  {
66  pitch = std::asin(sinp);
67  }
68 
69  // yaw (z-axis rotation)
70  double siny_cosp = 2 * (q.w * q.z + q.x * q.y);
71  double cosy_cosp = 1 - 2 * (q.y * q.y + q.z * q.z);
72  yaw = std::atan2(siny_cosp, cosy_cosp);
73 
74  const double RAD_TO_DEG = 180.0 / M_PI;
75  const double WRAP_ANGLE = M_PI*2.0;
76  const double WRAP_THRESHOLD = M_PI*1.95;
77 
78  //--------- wrap ------
79  if( (roll - _prev_roll) > WRAP_THRESHOLD ) {
80  _roll_offset -= WRAP_ANGLE;
81  }
82  else if( (_prev_roll - roll) > WRAP_THRESHOLD ) {
83  _roll_offset += WRAP_ANGLE;
84  }
85  _prev_roll = roll;
86 
87  if( (pitch - _prev_pitch) > WRAP_THRESHOLD ) {
88  _pitch_offset -= WRAP_ANGLE;
89  }
90  else if( (_prev_pitch - pitch) > WRAP_THRESHOLD ) {
91  _pitch_offset += WRAP_ANGLE;
92  }
93  _prev_pitch = pitch;
94 
95  if( (yaw - _prev_yaw) > WRAP_THRESHOLD ) {
96  _yaw_offset -= WRAP_ANGLE;
97  }
98  else if( (_prev_yaw - yaw) > WRAP_THRESHOLD ) {
99  _yaw_offset += WRAP_ANGLE;
100  }
101  _prev_yaw = yaw;
102  //---------------
103 
104  _data[4]->pushBack({ timestamp, RAD_TO_DEG * (roll + _roll_offset)});
105  _data[5]->pushBack({ timestamp, RAD_TO_DEG * (pitch + _pitch_offset) });
106  _data[6]->pushBack({ timestamp, RAD_TO_DEG * (yaw + _yaw_offset)});
107  }
108 
109  private:
110  std::vector<PJ::PlotData*> _data;
112  double _roll_offset;
113  double _yaw_offset;
114 
115  double _prev_pitch;
116  double _prev_roll;
117  double _prev_yaw;
118 
119  bool _initialized = false;
120 
121 };
void parseMessageImpl(const geometry_msgs::Quaternion &msg, double &timestamp) override
QuaternionMsgParser(const std::string &topic_name, PJ::PlotDataMapRef &plot_data)
#define M_PI_2
PJ::PlotData & getSeries(const std::string &key)
constexpr double RAD_TO_DEG
#define M_PI
std::string _topic_name
std::vector< PJ::PlotData * > _data


plotjuggler_ros
Author(s): Davide Faconti
autogenerated on Fri Jun 23 2023 02:28:03