nmea_gps_plugin.cpp
Go to the documentation of this file.
1 
13 
14 namespace gazebo
15 {
17  {
18 
19  }
20 
22  {
23 
24  }
25 
26  void NmeaGpsPlugin::Load(physics::ModelPtr model, sdf::ElementPtr sdf)
27  {
28  model_ptr_ = model;
29  world_ptr_ = model_ptr_->GetWorld();
30  if (!sdf->HasElement("robotNamespace"))
31  {
32  namespace_.clear();
33  }
34  else
35  {
36  namespace_ = sdf->GetElement("robotNamespace")->GetValue()->GetAsString();
37  }
38  if (!sdf->HasElement("bodyName"))
39  {
40  link_ptr_ = model_ptr_->GetLink();
41  link_name_ = link_ptr_->GetName();
42  }
43  else
44  {
45  link_name_ = sdf->GetElement("bodyName")->GetValue()->GetAsString();
46  link_ptr_ = model_ptr_->GetLink(link_name_);
47  }
57  if (sdf->HasElement("frameId"))
58  {
59  frame_id_ = sdf->GetElement("frameId")->GetValue()->GetAsString();
60  }
61  if (sdf->HasElement("topicName"))
62  {
63  nmea_topic_ = sdf->GetElement("topicName")->GetValue()->GetAsString();
64  }
65  if (sdf->HasElement("publishRate"))
66  {
67  sdf->GetElement("publishRate")->GetValue()->Get(publish_rate_);
68  }
69  if (sdf->HasElement("referenceLatitude"))
70  {
71  sdf->GetElement("referenceLatitude")->GetValue()->Get(reference_latitude_);
72  }
73  if (sdf->HasElement("referenceLongitude"))
74  {
75  sdf->GetElement("referenceLongitude")->GetValue()->Get(reference_longitude_);
76  }
77  if (sdf->HasElement("referenceHeading"))
78  {
79  if (sdf->GetElement("referenceHeading")->GetValue()->Get(reference_heading_))
80  {
82  }
83  }
84  if (sdf->HasElement("referenceAltitude"))
85  {
86  sdf->GetElement("referenceAltitude")->GetValue()->Get(reference_altitude_);
87  }
88  if (sdf->HasElement("positionGaussiaNoise"))
89  {
90  sdf->GetElement("positionGaussiaNoise")->GetValue()->Get(position_gaussiaa_noise_);
91  }
92  if (sdf->HasElement("orientationGaussiaNoise"))
93  {
94  sdf->GetElement("orientationGaussiaNoise")->GetValue()->Get(orientation_gaussian_noise_);
95  }
96  if (sdf->HasElement("velocityGaussiaNoise"))
97  {
98  sdf->GetElement("velocityGaussiaNoise")->GetValue()->Get(velocity_gaussian_noise_);
99  }
100  std::unique_ptr<GpsSensorModel> sensor_model_ptr(new GpsSensorModel(position_gaussiaa_noise_,orientation_gaussian_noise_,velocity_gaussian_noise_));
101  sensor_model_ptr_ = std::move(sensor_model_ptr);
103  nmea_pub_ = node_handle_.advertise<nmea_msgs::Sentence>(nmea_topic_,1);
104  initial_pose_.position.longitude = reference_longitude_;
105  initial_pose_.position.latitude = reference_latitude_;
106  initial_pose_.position.altitude = reference_altitude_;
107  geometry_msgs::Vector3 vec;
108  vec.x = 0.0;
109  vec.y = 0.0;
110  vec.z = reference_heading_;
113  update_connection_ = event::Events::ConnectWorldUpdateBegin(std::bind(&NmeaGpsPlugin::Update, this));
114  return;
115  }
116 
117  std::string NmeaGpsPlugin::getHexString(uint8_t value)
118  {
119  ROS_ASSERT(value <= 16);
120  std::string ret;
121  if(value == 10)
122  {
123  ret = "A";
124  }
125  else if(value == 11)
126  {
127  ret = "B";
128  }
129  else if(value == 12)
130  {
131  ret = "C";
132  }
133  else if(value == 13)
134  {
135  ret = "D";
136  }
137  else if(value == 14)
138  {
139  ret = "E";
140  }
141  else if(value == 15)
142  {
143  ret = "F";
144  }
145  else
146  {
147  ret = std::to_string(value);
148  }
149  return ret;
150  }
151 
152  std::string NmeaGpsPlugin::getCheckSum(std::string sentence)
153  {
154  uint8_t checksum;
155  for(int i=1; i<sentence.size(); i++)
156  {
157  int c = sentence[i];
158  checksum ^= c;
159  }
160  uint8_t rest = checksum%16;
161  uint8_t quotient = (checksum-rest)/16;
162  std::string ret = getHexString(quotient) + getHexString(rest);
163  ret = "*" + ret;
164  return ret;
165  }
166 
168  {
169  return;
170  }
171 
172  nmea_msgs::Sentence NmeaGpsPlugin::getGPGGA(ros::Time stamp)
173  {
174  nmea_msgs::Sentence sentence;
175  sentence.header.frame_id = frame_id_;
176  sentence.header.stamp = stamp;
177  sentence.sentence = "$GPGGA," + getUnixTime(stamp) + ",";
178  double lat = current_geo_pose_.position.latitude;
179  std::string north_or_south;
180  if(lat >= 0.0)
181  {
182  north_or_south = "N";
183  }
184  else
185  {
186  north_or_south = "S";
187  }
188  sentence.sentence = sentence.sentence + convertToDmm(lat) + "," + north_or_south + ",";
189  double lon = current_geo_pose_.position.longitude;
190  std::string east_or_west;
191  if(lon >= 0.0)
192  {
193  east_or_west = "E";
194  }
195  else
196  {
197  east_or_west = "W";
198  }
199  sentence.sentence = sentence.sentence + convertToDmm(lon) + "," + east_or_west + ",1,08,1.0,";
200  sentence.sentence = sentence.sentence + std::to_string(current_geo_pose_.position.altitude) + ",M,";
201  sentence.sentence = sentence.sentence + std::to_string(current_geo_pose_.position.altitude) + ",M,,0000";
202  sentence.sentence = sentence.sentence + getCheckSum(sentence.sentence);
203  return sentence;
204  }
205 
206  nmea_msgs::Sentence NmeaGpsPlugin::getGPRMC(ros::Time stamp)
207  {
208  nmea_msgs::Sentence sentence;
209  sentence.header.frame_id = frame_id_;
210  sentence.header.stamp = stamp;
211  sentence.sentence = "$GPRMC," + getUnixTime(stamp) + ",A,";
212  double lat = current_geo_pose_.position.latitude;
213  std::string north_or_south;
214  if(lat >= 0.0)
215  {
216  north_or_south = "N";
217  }
218  else
219  {
220  north_or_south = "S";
221  }
222  sentence.sentence = sentence.sentence + convertToDmm(lat) + "," + north_or_south + ",";
223  double lon = current_geo_pose_.position.longitude;
224  std::string east_or_west;
225  if(lon >= 0.0)
226  {
227  east_or_west = "E";
228  }
229  else
230  {
231  east_or_west = "W";
232  }
233  sentence.sentence = sentence.sentence + convertToDmm(lon) + "," + east_or_west + ",";
234  double vel = std::sqrt(std::pow(current_twist_.linear.x,2)+std::pow(current_twist_.linear.y,2)) * 1.94384; //[knot]
235  sentence.sentence = sentence.sentence + std::to_string(vel) + ",";
236  double angle = -1*std::atan2(current_twist_.linear.y,current_twist_.linear.x);
237  if(angle < 0)
238  {
239  angle = angle + 360.0;
240  }
241  angle = (double)(int)((angle*pow(10.0, 2)) + 0.9 ) * pow(10.0, -1);
242  sentence.sentence = sentence.sentence + std::to_string(angle) + ",";
243  sentence.sentence = sentence.sentence + getUnixDay(stamp) + ",,,";
244  sentence.sentence = sentence.sentence + "A";
245  sentence.sentence = sentence.sentence + getCheckSum(sentence.sentence);
246  return sentence;
247  }
248 
249  nmea_msgs::Sentence NmeaGpsPlugin::getGPVTG(ros::Time stamp)
250  {
251  nmea_msgs::Sentence sentence;
252  sentence.header.frame_id = frame_id_;
253  sentence.header.stamp = stamp;
254  sentence.sentence = "$GPVTG,";
255  double angle = -1*std::atan2(current_twist_.linear.y,current_twist_.linear.x);
256  if(angle < 0)
257  {
258  angle = angle + 360.0;
259  }
260  angle = (double)(int)((angle*pow(10.0, 2)) + 0.9 ) * pow(10.0, -1);
261  sentence.sentence = sentence.sentence + std::to_string(angle) + ",T,,M,";
262  double vel_knot = std::sqrt(std::pow(current_twist_.linear.x,2)+std::pow(current_twist_.linear.y,2)) * 1.94384; //[knot]
263  sentence.sentence = sentence.sentence + std::to_string(vel_knot) + ",N,";
264  double vel_kmph = std::sqrt(std::pow(current_twist_.linear.x,2)+std::pow(current_twist_.linear.y,2)) * 3.6; //[km/h]
265  sentence.sentence = sentence.sentence + std::to_string(vel_kmph) + ",K,";
266  sentence.sentence = sentence.sentence + ",A";
267  sentence.sentence = sentence.sentence + getCheckSum(sentence.sentence);
268  return sentence;
269  }
270 
271  nmea_msgs::Sentence NmeaGpsPlugin::getGPHDT(ros::Time stamp)
272  {
273  nmea_msgs::Sentence sentence;
274  sentence.header.frame_id = frame_id_;
275  sentence.header.stamp = stamp;
276  sentence.sentence = "$GPHDT,";
277  geometry_msgs::Vector3 vec = quaternion_operation::convertQuaternionToEulerAngle(current_geo_pose_.orientation);
278  double angle = -1*vec.z/M_PI*180;
279  if(angle < 0)
280  {
281  angle = angle + 360.0;
282  }
283  sentence.sentence = sentence.sentence + std::to_string(angle) + ",T";
284  sentence.sentence = sentence.sentence + getCheckSum(sentence.sentence);
285  return sentence;
286  }
287 
289  {
290  std::string ret;
291  time_t t = stamp.sec;
292  struct tm *utc_time;
293  utc_time = gmtime(&t);
294  int day = utc_time->tm_mday;
295  int month = utc_time->tm_mon;
296  int year = 1900 + utc_time->tm_year;
297  std::string year_str = std::to_string(year);
298  ret = std::to_string(day) + std::to_string(month) + year_str[2] + year_str[3];
299  return ret;
300  }
301 
303  {
304  std::string ret;
305  time_t t = stamp.sec;
306  struct tm *utc_time;
307  utc_time = gmtime(&t);
308  int hour = utc_time->tm_hour;
309  int min = utc_time->tm_min;
310  int sec = utc_time->tm_sec;
311  uint32_t nsec = stamp.nsec;
312  int csec = round((double)nsec/std::pow(10,7));
313  std::string hour_str;
314  if(hour<9)
315  {
316  hour_str = "0" + std::to_string(hour);
317  }
318  else
319  {
320  hour_str = std::to_string(hour);
321  }
322  std::string min_str;
323  if(min<=9)
324  {
325  min_str = "0" + std::to_string(min);
326  }
327  else
328  {
329  min_str = std::to_string(min);
330  }
331  std::string sec_str;
332  if(sec<=9)
333  {
334  sec_str = "0" + std::to_string(sec);
335  }
336  else
337  {
338  sec_str = std::to_string(sec);
339  }
340  ret = hour_str + min_str + sec_str + "." + std::to_string(csec);
341  return ret;
342  }
343 
345  {
346 #if (GAZEBO_MAJOR_VERSION >= 8)
347  common::Time sim_time = world_ptr_->SimTime();
348 #else
349  common::Time sim_time = world_ptr_->GetSimTime();
350 #endif
351  bool publish;
352  if(!last_publish_timestamp_ || sim_time-(*last_publish_timestamp_) > common::Time(1.0/publish_rate_))
353  {
354  last_publish_timestamp_ = sim_time;
355  publish = true;
356  }
357  if(!publish)
358  {
359  return;
360  }
361 #if (GAZEBO_MAJOR_VERSION >= 8)
362  ignition::math::Pose3d pose = link_ptr_->WorldPose();
363  ignition::math::Vector3d linear_velocity = link_ptr_->WorldLinearVel();
364  current_twist_.linear.x = linear_velocity.X();
365  current_twist_.linear.y = linear_velocity.Y();
366  current_twist_.linear.z = linear_velocity.Z();
367 #else
368  gazebo::math::Pose pose = link_ptr_->GetWorldPose();
369  gazebo::math::Vector3 linear_velocity = link_ptr_->GetWorldLinearVel();
370  current_twist_.linear.x = linear_velocity.x;
371  current_twist_.linear.y = linear_velocity.y;
372  current_twist_.linear.z = linear_velocity.z;
373 #endif
375  {
376  initial_gazebo_pose_ = pose;
377  }
378  current_twist_ = sensor_model_ptr_->addGaussianNoise(current_twist_);
379  ros::Time stamp;
380  stamp.sec = sim_time.sec;
381  stamp.nsec = sim_time.nsec;
382  geodesy::UTMPoint current_utm_point;
383  geometry_msgs::Quaternion current_utm_quat;
384 #if (GAZEBO_MAJOR_VERSION >= 8)
385  current_utm_quat.x = pose.Rot().X();
386  current_utm_quat.y = pose.Rot().Y();
387  current_utm_quat.z = pose.Rot().Z();
388  current_utm_quat.w = pose.Rot().W();
389  geometry_msgs::Vector3 current_utm_orientation
391  current_utm_orientation.z = current_utm_orientation.z + reference_heading_;
392  current_utm_quat = quaternion_operation::convertEulerAngleToQuaternion(current_utm_orientation);
393  double diff_x = pose.Pos().X() - initial_gazebo_pose_->Pos().X();
394  double diff_y = pose.Pos().Y() - initial_gazebo_pose_->Pos().Y();
395  double r = std::sqrt(diff_x*diff_x + diff_y*diff_y);
396  double theta = std::atan2(diff_y,diff_x) + reference_heading_;
397  current_utm_point.northing = initial_utm_pose_.position.northing + r*std::cos(theta);
398  current_utm_point.easting = initial_utm_pose_.position.easting - r*std::sin(theta);
399  current_utm_point.altitude = pose.Pos().Z() + initial_utm_pose_.position.altitude;
400 #else
401  current_utm_quat.x = pose.rot.x;
402  current_utm_quat.y = pose.rot.y;
403  current_utm_quat.z = pose.rot.z;
404  current_utm_quat.w = pose.rot.w;
405  geometry_msgs::Vector3 current_utm_orientation = quaternion_operation::convertQuaternionToEulerAngle(current_utm_quat);
406  current_utm_orientation.z = current_utm_orientation.z + reference_heading_;
407  current_utm_quat = quaternion_operation::convertEulerAngleToQuaternion(current_utm_orientation);
408  double diff_x = pose.pos.x - initial_gazebo_pose_->pos.x;
409  double diff_y = pose.pos.y - initial_gazebo_pose_->pos.y;
410  double r = std::sqrt(diff_x*diff_x + diff_y*diff_y);
411  double theta = std::atan2(diff_y,diff_x) + reference_heading_;
412  current_utm_point.northing = initial_utm_pose_.position.northing + r*std::cos(theta);
413  current_utm_point.easting = initial_utm_pose_.position.easting - r*std::sin(theta);
414  current_utm_point.altitude = pose.pos.z + initial_utm_pose_.position.altitude;
415 #endif
416  current_utm_point.zone = initial_utm_pose_.position.zone;
417  current_utm_point.band = initial_utm_pose_.position.band;
418  current_utm_point = sensor_model_ptr_->addGaussianNoise(current_utm_point);
419  current_utm_quat = sensor_model_ptr_->addGaussianNoise(current_utm_quat);
420  current_geo_pose_.position = geodesy::toMsg(current_utm_point);
421  current_geo_pose_.orientation = current_utm_quat;
422  nmea_pub_.publish(getGPRMC(stamp));
423  nmea_pub_.publish(getGPGGA(stamp));
424  nmea_pub_.publish(getGPVTG(stamp));
425  nmea_pub_.publish(getGPHDT(stamp));
426  return;
427  }
428 
429  std::string NmeaGpsPlugin::convertToDmm(double value)
430  {
431  std::string ret;
432  value = std::fabs(value);
433  int deg = std::floor(value);
434  std::stringstream ss;
435  ss << std::setprecision(7) << (value-(double)deg)*60.0;
436  ret = std::to_string(deg) + ss.str();
437  return ret;
438  }
439 
440  GZ_REGISTER_MODEL_PLUGIN(NmeaGpsPlugin)
441 }
virtual void Update()
Update the sensor state and publish nmea sentence.
geometry_msgs::Quaternion convertEulerAngleToQuaternion(geometry_msgs::Vector3 euler)
nmea_msgs::Sentence getGPVTG(ros::Time stamp)
generate GPVTG sentence
constexpr double reference_altitude
initial altitude of the robot
std::string getUnixTime(ros::Time stamp)
Get Unix time from the timestmap.
std::string getHexString(uint8_t value)
void publish(const boost::shared_ptr< M > &message) const
std::string getUnixDay(ros::Time stamp)
Get Unix day from the timestamp.
virtual void Load(physics::ModelPtr model, sdf::ElementPtr sdf)
Load parameters for the nmea gps plugin.
geodesy::UTMPose initial_utm_pose_
geographic_msgs::GeoPose current_geo_pose_
physics::ModelPtr model_ptr_
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
virtual void Reset()
Reset the nmea gps plugin.
std::string convertToDmm(double value)
Convert DDD -> DMM format.
constexpr double position_gaussiaa_noise
gaussian noise of the posision
constexpr double publish_rate
publish rate of the each sentence
static geographic_msgs::GeoPoint toMsg(double lat, double lon)
constexpr double reference_longitude
initial longitude of the robot
const std::string nmea_topic
topic name of the nmea_sentence topic
std::string getCheckSum(std::string sentence)
geometry_msgs::Twist current_twist_
boost::optional< gazebo::math::Pose > initial_gazebo_pose_
constexpr double reference_heading
nitial heading of the robot
boost::optional< common::Time > last_publish_timestamp_
nmea_msgs::Sentence getGPRMC(ros::Time stamp)
generate GPRMC sentence
std::unique_ptr< GpsSensorModel > sensor_model_ptr_
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
ros::Publisher nmea_pub_
geometry_msgs::Vector3 convertQuaternionToEulerAngle(geometry_msgs::Quaternion quat)
physics::WorldPtr world_ptr_
ros::NodeHandle node_handle_
int min(int a, int b)
definition for the NmeaGpsPlugin class
event::ConnectionPtr update_connection_
Class for the GPS sensor model.
geographic_msgs::GeoPose initial_pose_
constexpr double orientation_gaussian_noise
gaussian noise of the orientation
physics::LinkPtr link_ptr_
#define ROS_ASSERT(cond)
nmea_msgs::Sentence getGPHDT(ros::Time stamp)
Class of the NMEA gps plugin.
nmea_msgs::Sentence getGPGGA(ros::Time stamp)
generate GPGGA sentence
constexpr double velocity_gaussian_noise
gaussian noise of the velocity
constexpr double reference_latitude
initial longitude of the robot


nmea_gps_plugin
Author(s):
autogenerated on Wed Jul 17 2019 03:53:56