orbital_data_manager.cpp
Go to the documentation of this file.
1 // SPDX-License-Identifier: BSD-3-Clause
2 // SPDX-FileCopyrightText: Czech Technical University in Prague
3 
4 #include <limits>
5 #include <list>
6 #include <memory>
7 #include <string>
8 #include <unordered_map>
9 
10 #include <Eigen/Eigen>
11 
12 #include <angles/angles.h>
18 #include <gnss_info_msgs/SatellitesList.h>
19 #include <gnss_info_msgs/SatellitesPositions.h>
20 #include <gnss_info_msgs/SkyView.h>
21 #include <ros/ros.h>
22 
23 namespace gnss_info
24 {
25 
27 {
28  std::list<std::shared_ptr<OrbitalDataProvider>> providers;
29 
30  std::list<std::shared_ptr<OrbitalDataProvider>> getRelevantProviders(
31  const ros::Time& time, const cras::optional<bool>& precise) const;
32 
33  std::list<std::shared_ptr<OrbitalDataProvider>> getRelevantProviders(
34  const ros::Time& startTime, const ros::Time& endTime, const cras::optional<bool>& precise) const;
35 };
36 
37 std::list<std::shared_ptr<OrbitalDataProvider>> OrbitalDataManagerPrivate::getRelevantProviders(
38  const ros::Time& time, const cras::optional<bool>& precise) const
39 {
40  return this->getRelevantProviders(time, time, precise);
41 }
42 
43 std::list<std::shared_ptr<OrbitalDataProvider>> OrbitalDataManagerPrivate::getRelevantProviders(
44  const ros::Time& startTime, const ros::Time& endTime, const cras::optional<bool>& precise) const
45 {
46  std::list<std::shared_ptr<OrbitalDataProvider>> result;
47  for (const auto& provider : this->providers)
48  {
49  if (precise.has_value() && *precise && !provider->isPrecise())
50  continue;
51  if (precise.has_value() && !*precise && !provider->isApproximate())
52  continue;
53  if (startTime > provider->getTimeRange().second)
54  continue;
55  if (endTime < provider->getTimeRange().first)
56  continue;
57  result.push_back(provider);
58  }
59  return result;
60 }
61 
63 {
64 }
65 
67 
69 {
70  return this->load(time, cras::nullopt);
71 }
72 
73 bool OrbitalDataManager::load(const ros::Time& time, const cras::optional<bool>& precise)
74 {
75  for (const auto& provider : this->data->getRelevantProviders(time, precise))
76  {
77  if (provider->load(time, precise))
78  return true;
79  }
80  ROS_ERROR_THROTTLE(1.0, "No orbit data provider loaded for time %s.", cras::to_string(time).c_str());
81  return false;
82 }
83 
84 bool OrbitalDataManager::load(const ros::Time& startTime, const ros::Time& endTime)
85 {
86  return this->load(startTime, endTime, cras::nullopt);
87 }
88 
90  const ros::Time& startTime, const ros::Time& endTime, const cras::optional<bool>& precise)
91 {
92  for (const auto& provider : this->data->getRelevantProviders(startTime, endTime, precise))
93  {
94  if (provider->load(startTime, endTime, precise))
95  return true;
96  }
97  ROS_ERROR_THROTTLE(1.0, "No orbit data provider loaded between %s and %s.",
98  cras::to_string(startTime).c_str(), cras::to_string(endTime).c_str());
99  return false;
100 }
101 
102 cras::expected<gnss_info_msgs::SatellitesPositions, std::string> OrbitalDataManager::getPositions(
103  const ros::Time& time, const gnss_info_msgs::SatellitesList& satellites)
104 {
105  return this->getPositions(time, satellites, cras::nullopt);
106 }
107 
108 cras::expected<gnss_info_msgs::SatellitesPositions, std::string> OrbitalDataManager::getPositions(
109  const ros::Time& time, const gnss_info_msgs::SatellitesList& satellites, const cras::optional<bool>& precise)
110 {
111  this->load(time, precise);
112  const auto providers = this->data->getRelevantProviders(time, precise);
113  if (providers.empty())
114  return cras::make_unexpected("No satellite data was found");
115 
116  std::unordered_map<uint32_t, gnss_info_msgs::SatelliteInfo> sats;
117  for (const auto& sat : satellites.satellites)
118  sats[sat.satcat_id] = sat;
119 
120  for (const auto& provider : providers)
121  {
122  const auto maybePositions = provider->getECEFPositions(time, sats);
123  if (!maybePositions.has_value())
124  {
125  ROS_DEBUG("Failed getting positions from provider %s at time %s: %s",
126  provider->getName().c_str(), cras::to_string(time).c_str(), maybePositions.error().c_str());
127  continue;
128  }
129 
130  const auto& positions = *maybePositions;
131  if (positions.empty())
132  continue;
133 
134  gnss_info_msgs::SatellitesPositions msg;
135  msg.header.stamp = time;
136  msg.header.frame_id = "ecef";
137  for (const auto& [satcatId, pos] : positions)
138  msg.satellites.push_back(pos);
139  return msg;
140  }
141  return cras::make_unexpected("Could not find a provider for satellite ECEF positions.");
142 }
143 
144 cras::expected<gnss_info_msgs::SkyView, std::string> OrbitalDataManager::getSkyView(
145  const geographic_msgs::GeoPoint& position, const gnss_info_msgs::SatellitesPositions& positions,
146  const double elevationMaskDeg)
147 {
148  return this->getSkyView(position, positions, elevationMaskDeg, cras::nullopt);
149 }
150 
151 cras::expected<gnss_info_msgs::SkyView, std::string> OrbitalDataManager::getSkyView(
152  const geographic_msgs::GeoPoint& position, const gnss_info_msgs::SatellitesPositions& positions,
153  const double elevationMaskDeg, const cras::optional<bool>& precise)
154 {
155  this->load(positions.header.stamp, precise);
156  const auto providers = this->data->getRelevantProviders(positions.header.stamp, precise);
157  if (providers.empty())
158  return cras::make_unexpected("No satellite data was found");
159 
160  std::unordered_map<uint32_t, gnss_info_msgs::SatellitePosition> positionsMap;
161  for (const auto& pos : positions.satellites)
162  positionsMap[pos.satcat_id] = pos;
163 
164  for (const auto& provider : providers)
165  {
166  const auto maybeSkyView = provider->getSkyView(position, positionsMap, elevationMaskDeg);
167  if (!maybeSkyView.has_value())
168  {
169  ROS_DEBUG("Failed getting sky view from provider %s at time %s: %s",
170  provider->getName().c_str(), cras::to_string(time).c_str(), maybeSkyView.error().c_str());
171  continue;
172  }
173 
174  const auto& skyView = *maybeSkyView;
175  gnss_info_msgs::SkyView msg;
176  msg.header.stamp = positions.header.stamp;
177  msg.header.frame_id = "WGS84";
178  msg.elevation_mask_deg = elevationMaskDeg;
179  msg.reference_position = position;
180  for (const auto& [satcatId, sat] : skyView)
181  msg.satellites.push_back(sat);
182  msg.dop = this->computeDOP(skyView);
183  return msg;
184  }
185 
186  return cras::make_unexpected("Could not find a provider for satellite sky positions.");
187 }
188 
189 gnss_info_msgs::DOP OrbitalDataManager::computeDOP(
190  const std::unordered_map<uint32_t, gnss_info_msgs::SatelliteSkyPosition>& skyView) const
191 {
192  // https://en.wikipedia.org/wiki/Dilution_of_precision_(navigation)#Computation
193  // rtklib uses exactly the same algorithm in dops().
194 
195  gnss_info_msgs::DOP dop;
196 
197  if (skyView.size() < 4)
198  {
199  dop.gdop = dop.pdop = dop.hdop = dop.vdop = dop.tdop = std::numeric_limits<float>::infinity();
200  return dop;
201  }
202 
203  Eigen::MatrixX4d A(skyView.size(), 4);
204  Eigen::Index i{0};
205  for (const auto& [satcatId, skyPos] : skyView)
206  {
207  const auto az = angles::from_degrees(skyPos.azimuth_deg);
208  const auto el = angles::from_degrees(skyPos.elevation_deg);
209  A(i, 0) = std::cos(el) * std::sin(az);
210  A(i, 1) = std::cos(el) * std::cos(az);
211  A(i, 2) = std::sin(el);
212  A(i, 3) = 1.0;
213  ++i;
214  }
215 
216  const Eigen::Matrix4d Q = (A.transpose() * A).inverse();
217  dop.tdop = std::sqrt(Q(3, 3));
218  dop.vdop = std::sqrt(Q(2, 2));
219  dop.hdop = std::sqrt(Q(0, 0) + Q(1, 1));
220  dop.pdop = std::sqrt(Q(0, 0) + Q(1, 1) + Q(2, 2));
221  dop.gdop = std::sqrt(Q(0, 0) + Q(1, 1) + Q(2, 2) + Q(3, 3));
222 
223  return dop;
224 }
225 
226 void OrbitalDataManager::addProvider(const std::shared_ptr<OrbitalDataProvider>& provider)
227 {
228  this->data->providers.push_back(provider);
229 }
230 
231 }
optional.hpp
ROS_ERROR_THROTTLE
#define ROS_ERROR_THROTTLE(period,...)
msg
msg
gnss_info::OrbitalDataManager::data
std::unique_ptr< OrbitalDataManagerPrivate > data
Private implementation details (PIMPL).
Definition: orbital_data_manager.h:122
angles::from_degrees
static double from_degrees(double degrees)
gnss_info::OrbitalDataManager::computeDOP
virtual gnss_info_msgs::DOP computeDOP(const std::unordered_map< uint32_t, gnss_info_msgs::SatelliteSkyPosition > &skyView) const
Compute Dilution of Precision for the given sky view.
Definition: orbital_data_manager.cpp:189
ros.h
gnss_info::OrbitalDataManagerPrivate::providers
std::list< std::shared_ptr< OrbitalDataProvider > > providers
Definition: orbital_data_manager.cpp:28
inverse
Matrix< T > inverse(const ConstMatrixBase< T, BaseClass > &m)
data
data
gnss_info::OrbitalDataManagerPrivate::getRelevantProviders
std::list< std::shared_ptr< OrbitalDataProvider > > getRelevantProviders(const ros::Time &time, const cras::optional< bool > &precise) const
Definition: orbital_data_manager.cpp:37
std::sin
double sin(gnsstk::Angle x)
string_utils.hpp
gnss_info::OrbitalDataManager::~OrbitalDataManager
virtual ~OrbitalDataManager()
ROS_DEBUG
#define ROS_DEBUG(...)
time
time
gnss_info::OrbitalDataManagerPrivate
Definition: orbital_data_manager.cpp:26
gnss_info::OrbitalDataManager::load
bool load(const ros::Time &time)
Load (and possibly download) data for the given time instant.
Definition: orbital_data_manager.cpp:68
gnss_info
Definition: cache.h:15
gnss_info::OrbitalDataManager::getPositions
cras::expected< gnss_info_msgs::SatellitesPositions, std::string > getPositions(const ros::Time &time, const gnss_info_msgs::SatellitesList &satellites)
Compute ECEF positions of the satellites at the given time.
Definition: orbital_data_manager.cpp:102
std::cos
double cos(gnsstk::Angle x)
pos
pos
orbital_data_manager.h
expected.hpp
orbital_data_provider.h
gnss_info::OrbitalDataManager::addProvider
void addProvider(const std::shared_ptr< OrbitalDataProvider > &provider)
Add the given provider to this manager and make its data available.
Definition: orbital_data_manager.cpp:226
gnss_info::OrbitalDataManager::getSkyView
cras::expected< gnss_info_msgs::SkyView, std::string > getSkyView(const geographic_msgs::GeoPoint &position, const gnss_info_msgs::SatellitesPositions &positions, double elevationMaskDeg)
Compute sky view (azimuths, elevations and distances) of satellites from the given receiver position.
Definition: orbital_data_manager.cpp:144
ros::Time
gnss_info::OrbitalDataManager::OrbitalDataManager
OrbitalDataManager()
Definition: orbital_data_manager.cpp:62
angles.h
cras::to_string
inline ::std::string to_string(char *value)


gnss_info
Author(s): Martin Pecka
autogenerated on Fri Nov 24 2023 03:50:35