global_reference.cpp
Go to the documentation of this file.
1 //=================================================================================================
2 // Copyright (c) 2012, Johannes Meyer, TU Darmstadt
3 // All rights reserved.
4 
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // * Neither the name of the Flight Systems and Automatic Control group,
13 // TU Darmstadt, nor the names of its contributors may be used to
14 // endorse or promote products derived from this software without
15 // specific prior written permission.
16 
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 //=================================================================================================
28 
31 #include <cmath>
32 
33 #include <ros/console.h>
34 
35 using namespace std;
36 
37 namespace hector_pose_estimation {
38 
39 GlobalReference::GlobalReference()
40 {
41  parameters().add("reference_latitude", reference_latitude_ = std::numeric_limits<double>::quiet_NaN());
42  parameters().add("reference_longitude", reference_longitude_ = std::numeric_limits<double>::quiet_NaN());
43  parameters().add("reference_altitude", reference_altitude_ = std::numeric_limits<double>::quiet_NaN());
44  parameters().add("reference_heading", heading_.value = std::numeric_limits<double>::quiet_NaN());
45 
46  reset();
47 }
48 
49 const GlobalReferencePtr &GlobalReference::Instance()
50 {
51  static GlobalReferencePtr instance;
52  if (!instance) { instance.reset(new GlobalReference); }
53  return instance;
54 }
55 
56 void GlobalReference::reset()
57 {
58  position_ = Position();
59  heading_ = Heading();
60  radius_ = Radius();
61 
62  // parameters are in degrees
63  position_.latitude = reference_latitude_ * M_PI/180.0;
64  position_.longitude = reference_longitude_ * M_PI/180.0;
65  position_.altitude = reference_altitude_;
66  heading_.value = reference_heading_;
67 
68  updated();
69 }
70 
71 ParameterList& GlobalReference::parameters() {
72  return parameters_;
73 }
74 
75 void GlobalReference::updated(bool intermediate) {
76  // calculate earth radii
77  if (hasPosition()) {
78  radius_ = Radius(position_.latitude);
79  }
80 
81  // calculate sin and cos of the heading reference
82  if (hasHeading()) {
83  sincos(heading_.value, &heading_.sin, &heading_.cos);
84  }
85 
86  // execute update callbacks
87  if (!intermediate) {
88  for(std::list<UpdateCallback>::iterator cb = update_callbacks_.begin(); cb != update_callbacks_.end(); ++cb)
89  (*cb)();
90  }
91 }
92 
93 GlobalReference::Heading::Heading(double heading) : value(heading)
94 {
95  sincos(heading, &sin, &cos);
96 }
97 
99 {
100  double sin_2, cos_2;
101  sincos(0.5 * value, &sin_2, &cos_2);
102  return Quaternion(cos_2, 0.0, 0.0, -sin_2);
103 }
104 
106  // WGS84 constants
107  static const double equatorial_radius = 6378137.0;
108  static const double flattening = 1.0/298.257223563;
109  static const double excentrity2 = 2*flattening - flattening*flattening;
110 
111  double temp = 1.0 / (1.0 - excentrity2 * sin(latitude) * sin(latitude));
112  double prime_vertical_radius = equatorial_radius * sqrt(temp);
113  north = prime_vertical_radius * (1 - excentrity2) * temp;
114  east = prime_vertical_radius * cos(latitude);
115 }
116 
117 void GlobalReference::fromWGS84(double latitude, double longitude, double &x, double &y) {
118  if (!hasPosition()) {
119  x = 0.0;
120  y = 0.0;
121  return;
122  }
123  double north = radius_.north * (latitude - position_.latitude);
124  double east = radius_.east * (longitude - position_.longitude);
125  fromNorthEast(north, east, x, y);
126 }
127 
128 void GlobalReference::toWGS84(double x, double y, double &latitude, double &longitude) {
129  if (!hasPosition()) {
130  latitude = 0.0;
131  longitude = 0.0;
132  return;
133  }
134 
135  double north, east;
136  toNorthEast(x, y, north, east);
137  latitude = position_.latitude + north / radius_.north;
138  longitude = position_.longitude + east / radius_.east;
139 }
140 
141 void GlobalReference::fromNorthEast(double north, double east, double &x, double &y) {
142  if (!hasHeading()) {
143  x = 0.0;
144  y = 0.0;
145  return;
146  }
147  x = north * heading_.cos + east * heading_.sin;
148  y = north * heading_.sin - east * heading_.cos;
149 }
150 
151 void GlobalReference::toNorthEast(double x, double y, double &north, double &east) {
152  if (!hasHeading()) {
153  north = 0.0;
154  east = 0.0;
155  return;
156  }
157  north = x * heading_.cos + y * heading_.sin;
158  east = x * heading_.sin - y * heading_.cos;
159 }
160 
161 GlobalReference& GlobalReference::setPosition(double latitude, double longitude, bool intermediate /* = false */) {
162  position_.latitude = latitude;
163  position_.longitude = longitude;
164  if (!intermediate) ROS_INFO("Set new reference position to %f deg N / %f deg E", this->position().latitude * 180.0/M_PI, this->position().longitude * 180.0/M_PI);
165  updated(intermediate);
166  return *this;
167 }
168 
169 GlobalReference& GlobalReference::setHeading(double heading, bool intermediate /* = false */) {
171  if (!intermediate) ROS_INFO("Set new reference heading to %.1f degress", this->heading() * 180.0 / M_PI);
172  updated(intermediate);
173  return *this;
174 }
175 
176 GlobalReference& GlobalReference::setAltitude(double altitude, bool intermediate /* = false */) {
177  position_.altitude = altitude;
178  if (!intermediate) ROS_INFO("Set new reference altitude to %.2f m", this->position().altitude);
179  updated(intermediate);
180  return *this;
181 }
182 
183 GlobalReference& GlobalReference::setCurrentPosition(const State& state, double new_latitude, double new_longitude) {
185 
186  // set reference to new latitude/longitude first (intermediate reference)
187  setPosition(new_latitude, new_longitude, true);
188 
189  // convert current position back to WGS84 using the new reference position
190  // and reset the reference position so that current position in x/y coordinates remains the same
191  // This will work unless the radii at the origin and the x/y position of the robot differ too much
192  toWGS84(-position.x(), -position.y(), new_latitude, new_longitude);
193  setPosition(new_latitude, new_longitude);
194 
195  return *this;
196 }
197 
198 GlobalReference& GlobalReference::setCurrentHeading(const State& state, double new_heading) {
199  // get current yaw angle
200  double current_yaw = state.getYaw();
202 
203  // get current position in WGS84
204  double current_latitude, current_longitude;
205  if (hasPosition()) {
206  toWGS84(position.x(), position.y(), current_latitude, current_longitude);
207  }
208 
209  // set the new reference heading
210  setHeading(new_heading - (-current_yaw));
211 
212  // set the new reference position so that current position in WGS84 coordinates remains the same as before
213  if (hasPosition()) {
214  setCurrentPosition(state, current_latitude, current_longitude);
215  }
216 
217  return *this;
218 }
219 
220 GlobalReference& GlobalReference::setCurrentAltitude(const State& state, double new_altitude) {
222  setAltitude(new_altitude - position.z());
223  return *this;
224 }
225 
226 void GlobalReference::getGeoPose(geographic_msgs::GeoPose& geopose) const
227 {
228  Quaternion orientation(heading().quaternion());
229  geopose.orientation.w = orientation.w();
230  geopose.orientation.x = orientation.x();
231  geopose.orientation.y = orientation.y();
232  geopose.orientation.z = orientation.z();
233  geopose.position.latitude = position().latitude * 180.0/M_PI;
234  geopose.position.longitude = position().longitude * 180.0/M_PI;
235  geopose.position.altitude = position().altitude;
236 }
237 
238 bool GlobalReference::getWorldToNavTransform(geometry_msgs::TransformStamped& transform, const std::string &world_frame, const std::string &nav_frame, const ros::Time& stamp) const
239 {
240  // Return transform from world_frame (defined by parameters reference_latitude_, reference_longitude_, reference_altitude_ and reference_heading_)
241  // to the nav_frame (this reference)
242  if (isnan(reference_latitude_) ||
243  isnan(reference_longitude_) ||
244  isnan(reference_altitude_) ||
245  isnan(reference_heading_)) {
246  return false;
247  }
248 
249  transform.header.stamp = stamp;
250  transform.header.frame_id = world_frame;
251  transform.child_frame_id = nav_frame;
252 
253  Radius reference_radius(reference_latitude_ * M_PI/180.0);
254  double north = reference_radius.north * (position_.latitude - reference_latitude_ * M_PI/180.0);
255  double east = reference_radius.east * (position_.longitude - reference_longitude_ * M_PI/180.0);
256  Heading reference_heading(reference_heading_ * M_PI/180.0);
257  transform.transform.translation.x = north * reference_heading.cos + east * reference_heading.sin;
258  transform.transform.translation.y = north * reference_heading.sin - east * reference_heading.cos;
259  transform.transform.translation.z = position_.altitude - reference_altitude_;
260  double heading_diff = heading().value - reference_heading;
261  transform.transform.rotation.w = cos(heading_diff / 2.);
262  transform.transform.rotation.x = 0.0;
263  transform.transform.rotation.y = 0.0;
264  transform.transform.rotation.z = -sin(heading_diff / 2.);
265 
266  return true;
267 }
268 
270 {
271  update_callbacks_.push_back(cb);
272 }
273 
274 } // namespace hector_pose_estimation
bool getWorldToNavTransform(geometry_msgs::TransformStamped &transform, const std::string &world_frame, const std::string &nav_frame, const ros::Time &stamp=ros::Time()) const
Measurement_< HeadingModel > Heading
Definition: heading.h:53
void fromWGS84(double latitude, double longitude, double &x, double &y)
void toWGS84(double x, double y, double &latitude, double &longitude)
std::list< UpdateCallback > update_callbacks_
void toNorthEast(double x, double y, double &north, double &east)
GlobalReference & setCurrentAltitude(const State &state, double altitude)
Eigen::Quaternion< ScalarType > Quaternion
Definition: matrix.h:49
void addUpdateCallback(const UpdateCallback &)
GlobalReference & setCurrentHeading(const State &state, double heading)
#define ROS_INFO(...)
GlobalReference & setAltitude(double altitude, bool intermediate=false)
GlobalReference & setCurrentPosition(const State &state, double latitude, double longitude)
double getYaw() const
Definition: state.cpp:139
void getGeoPose(geographic_msgs::GeoPose &geopose) const
GlobalReference & setPosition(double latitude, double longitude, bool intermediate=false)
void fromNorthEast(double north, double east, double &x, double &y)
VectorBlock< const Vector, 3 > ConstPositionType
Definition: state.h:61
void updated(bool intermediate=false)
virtual ConstPositionType getPosition() const
Definition: state.cpp:118
GlobalReference & setHeading(double heading, bool intermediate=false)


hector_pose_estimation_core
Author(s): Johannes Meyer
autogenerated on Thu Feb 18 2021 03:29:30