NASA Astrobee Robot Software  0.19.1
Flight software for the Astrobee robots operating inside the International Space Station.
timestamped_combined_nodes.h
Go to the documentation of this file.
1 /* Copyright (c) 2017, United States Government, as represented by the
2  * Administrator of the National Aeronautics and Space Administration.
3  *
4  * All rights reserved.
5  *
6  * The Astrobee platform is licensed under the Apache License, Version 2.0
7  * (the "License"); you may not use this file except in compliance with the
8  * License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15  * License for the specific language governing permissions and limitations
16  * under the License.
17  */
18 
19 #ifndef NODES_TIMESTAMPED_COMBINED_NODES_H_
20 #define NODES_TIMESTAMPED_COMBINED_NODES_H_
21 
24 #include <nodes/values.h>
25 
26 #include <gtsam/nonlinear/NonlinearFactorGraph.h>
27 
28 #include <boost/optional.hpp>
29 #include <boost/serialization/serialization.hpp>
30 
31 #include <map>
32 #include <utility>
33 #include <vector>
34 
35 namespace nodes {
36 template <typename NodeType>
37 // Container for timestamped nodes with multiple values per node.
38 // Enables a NodeAdder to couple multiple values at the same timestamp that are always added and updated together into a
39 // single combined node. For example, a visual-intertial NodeAdder may always add and update pose, velocity, and
40 // IMU-biases together and never individually, so these should be grouped into a combined node rather than treated
41 // separately. The Add and Node functions must be specialized for the desired combined node. For nodes with a single
42 // value, such as just a pose or position, use TimestampedNodes, which is a specialization of TimestampedCombinedNodes
43 // with CombinedType = false.
45  public:
46  // Values should be provided by a graph optimizer and the same values
47  // should be passed to all timestamped nodes in the graph.
48  explicit TimestampedCombinedNodes(std::shared_ptr<Values> values);
49 
50  // For serialization only
51  TimestampedCombinedNodes() = default;
52 
53  virtual ~TimestampedCombinedNodes() = default;
54 
55  // Add a node at the provided timestamp and return the GTSAM keys that correspond to it.
56  // The keys are used in graph factors to connect a factor to a node.
57  // Note that a single node can have multiple keys, for example a pose velocity node
58  // may have a pose key and velocity key. The ordering of keys is set in the specialized
59  // Add(node) function for the NodeType.
60  gtsam::KeyVector Add(const localization_common::Time timestamp, const NodeType& node);
61 
62  // Returns a node at the provided timestamp if it exists.
63  boost::optional<NodeType> Node(const localization_common::Time timestamp) const;
64 
65  // Returns a portion of a combined node (or a full non-combined node)
66  // with the provided key if it exists.
67  // To return a combined node, use Node(timestamp) instead.
68  template <typename T>
69  boost::optional<T> Value(const gtsam::Key& key) const;
70 
71  // Returns the keys for a timestamped node given the timestamp if it exists.
72  // If not, an empty key vector is returned.
73  gtsam::KeyVector Keys(const localization_common::Time timestamp) const;
74 
75  // Removes a node at the provided timestamp if it exists.
76  // Returns if a node was successfully removed.
77  bool Remove(const localization_common::Time& timestamp);
78 
79  // Returns the number of nodes. This does not return the number of values,
80  // so if one combined node containing a pose and velocity exists, this will
81  // return 1 for example.
82  size_t size() const;
83 
84  // Returns if there node container is empty.
85  bool empty() const;
86 
87  // Returns the oldest timestamp of the nodes in the container.
88  // Returns boost::none if no nodes exists.
89  boost::optional<localization_common::Time> OldestTimestamp() const;
90 
91  // Returns the oldest nodes in the container.
92  // Returns boost::none if no nodes exists.
93  boost::optional<NodeType> OldestNode() const;
94 
95  // Returns the latest timestamp of the nodes in the container.
96  // Returns boost::none if no nodes exists.
97  boost::optional<localization_common::Time> LatestTimestamp() const;
98 
99  // Returns the latest node in the container.
100  // Returns boost::none if no nodes exists.
101  boost::optional<NodeType> LatestNode() const;
102 
103  // Returns lower and upper time bounds for the provided timestamp. Equal values are set as lower and upper bound.
104  std::pair<boost::optional<localization_common::Time>, boost::optional<localization_common::Time>>
106 
107  // Return lower and upper node bounds for the provided timestamp. Equal values are set as lower and upper bound.
108  std::pair<boost::optional<NodeType>, boost::optional<NodeType>> LowerAndUpperBoundNodes(
109  const localization_common::Time timestamp) const;
110 
111  // Returns the closest node in time to the provided timestamp.
112  boost::optional<NodeType> ClosestNode(const localization_common::Time timestamp) const;
113 
114  // Returns the closest node timestamp to the provided timestamp.
115  boost::optional<localization_common::Time> ClosestTimestamp(const localization_common::Time timestamp) const;
116 
117  // Returns the lower bounded or equal in time timestamped node to the provided timestamp.
118  boost::optional<localization_common::TimestampedValue<NodeType>> LowerBoundOrEqual(
119  const localization_common::Time timestamp) const;
120 
121  // Returns all nodes older than the provided oldest_allowed_timestamp.
122  std::vector<NodeType> OldNodes(const localization_common::Time oldest_allowed_timestamp) const;
123 
124  // Returns keys for all nodes older than the provied oldest_allowed_timestamp.
125  gtsam::KeyVector OldKeys(const localization_common::Time oldest_allowed_timestamp) const;
126 
127  // Removes nodes older than the provied timestamp.
128  // Returns the number of removed nodes.
129  int RemoveOldNodes(const localization_common::Time oldest_allowed_timestamp);
130 
131  // Returns a vector containing the timestamps of all nodes in the container.
132  // Timestamps are sorted from oldest to latest.
133  std::vector<localization_common::Time> Timestamps() const;
134 
135  // Returns the total duration of node timestamps in the container.
136  double Duration() const;
137 
138  // Returns whether the container contains a node at the provided timestamp.
139  bool Contains(const localization_common::Time timestamp) const;
140 
141  // Const accessor for internal gtsam values.
142  const gtsam::Values& gtsam_values() const;
143 
144  protected:
145  std::shared_ptr<Values> values_;
146 
147  private:
148  // Removes a node with the provided keys if it exists.
149  bool Remove(const gtsam::KeyVector& keys);
150 
151  // Adds a node and returns the keys associated with it.
152  virtual gtsam::KeyVector AddNode(const NodeType& node) = 0;
153 
154  // Helper function that returns a node with the provied keys and timestamp if it exists.
155  virtual boost::optional<NodeType> GetNode(const gtsam::KeyVector& keys,
156  const localization_common::Time timestamp) const = 0;
157 
158  // Helper function that returns a node with the provided timestamped keys if it exists.
159  boost::optional<NodeType> Node(const localization_common::TimestampedValue<gtsam::KeyVector>& timestamped_keys) const;
160 
161  friend class boost::serialization::access;
162  template <class ARCHIVE>
163  void serialize(ARCHIVE& ar, const unsigned int /*version*/);
164 
166 };
167 
168 // Implementation
169 template <typename NodeType>
171  : values_(std::move(values)) {}
172 
173 template <typename NodeType>
175  const NodeType& node) {
176  if (Contains(timestamp)) return gtsam::KeyVector();
177  gtsam::KeyVector keys = AddNode(node);
178  timestamp_keys_map_.Add(timestamp, keys);
179  return keys;
180 }
181 
182 template <typename NodeType>
183 boost::optional<NodeType> TimestampedCombinedNodes<NodeType>::Node(const localization_common::Time timestamp) const {
184  const auto keys = Keys(timestamp);
185  if (keys.empty()) return boost::none;
186  return GetNode(keys, timestamp);
187 }
188 
189 template <typename NodeType>
190 boost::optional<NodeType> TimestampedCombinedNodes<NodeType>::Node(
191  const localization_common::TimestampedValue<gtsam::KeyVector>& timestamped_keys) const {
192  return GetNode(timestamped_keys.value, timestamped_keys.timestamp);
193 }
194 
195 template <typename NodeType>
196 template <typename T>
197 boost::optional<T> TimestampedCombinedNodes<NodeType>::Value(const gtsam::Key& key) const {
198  return values_->Value<T>(key);
199 }
200 
201 template <typename NodeType>
203  if (!Contains(timestamp)) return {};
204  return (timestamp_keys_map_.Get(timestamp))->value;
205 }
206 
207 template <typename NodeType>
209  const auto value = timestamp_keys_map_.Get(timestamp);
210  if (!value) return false;
211  bool successful_removal = true;
212  successful_removal = successful_removal && timestamp_keys_map_.Remove(timestamp);
213  successful_removal = successful_removal && Remove(value->value);
214  return successful_removal;
215 }
216 
217 template <typename NodeType>
218 bool TimestampedCombinedNodes<NodeType>::Remove(const gtsam::KeyVector& keys) {
219  return values_->Remove(keys);
220 }
221 
222 template <typename NodeType>
224  return timestamp_keys_map_.size();
225 }
226 
227 template <typename NodeType>
229  return timestamp_keys_map_.empty();
230 }
231 
232 template <typename NodeType>
233 boost::optional<localization_common::Time> TimestampedCombinedNodes<NodeType>::OldestTimestamp() const {
234  const auto oldest = timestamp_keys_map_.Oldest();
235  if (!oldest) return boost::none;
236  return oldest->timestamp;
237 }
238 
239 template <typename NodeType>
240 boost::optional<NodeType> TimestampedCombinedNodes<NodeType>::OldestNode() const {
241  const auto oldest = timestamp_keys_map_.Oldest();
242  if (!oldest) return boost::none;
243  return Node(*oldest);
244 }
245 
246 template <typename NodeType>
247 boost::optional<localization_common::Time> TimestampedCombinedNodes<NodeType>::LatestTimestamp() const {
248  const auto latest = timestamp_keys_map_.Latest();
249  if (!latest) return boost::none;
250  return latest->timestamp;
251 }
252 
253 template <typename NodeType>
254 boost::optional<NodeType> TimestampedCombinedNodes<NodeType>::LatestNode() const {
255  const auto latest = timestamp_keys_map_.Latest();
256  if (!latest) return boost::none;
257  return Node(*latest);
258 }
259 
260 template <typename NodeType>
261 std::pair<boost::optional<localization_common::Time>, boost::optional<localization_common::Time>>
263  const auto lower_and_upper_bound = timestamp_keys_map_.LowerAndUpperBound(timestamp);
264  boost::optional<localization_common::Time> lower_bound;
265  if (!lower_and_upper_bound.first)
266  lower_bound = boost::none;
267  else
268  lower_bound = lower_and_upper_bound.first->timestamp;
269  boost::optional<localization_common::Time> upper_bound;
270  if (!lower_and_upper_bound.second)
271  upper_bound = boost::none;
272  else
273  upper_bound = lower_and_upper_bound.second->timestamp;
274  return {lower_bound, upper_bound};
275 }
276 
277 template <typename NodeType>
278 std::pair<boost::optional<NodeType>, boost::optional<NodeType>>
280  const auto lower_and_upper_bound = timestamp_keys_map_.LowerAndUpperBound(timestamp);
281  boost::optional<NodeType> lower_bound;
282  if (!lower_and_upper_bound.first)
283  lower_bound = boost::none;
284  else
285  lower_bound = Node(*(lower_and_upper_bound.first));
286  boost::optional<NodeType> upper_bound;
287  if (!lower_and_upper_bound.second)
288  upper_bound = boost::none;
289  else
290  upper_bound = Node(*(lower_and_upper_bound.second));
291  return {lower_bound, upper_bound};
292 }
293 
294 template <typename NodeType>
295 boost::optional<localization_common::TimestampedValue<NodeType>> TimestampedCombinedNodes<NodeType>::LowerBoundOrEqual(
296  const localization_common::Time timestamp) const {
297  const auto lower_bound_or_equal = timestamp_keys_map_.LowerBoundOrEqual(timestamp);
298  if (!lower_bound_or_equal) return boost::none;
299  const auto node = Node(lower_bound_or_equal->timestamp);
300  if (!node) return boost::none;
301  return localization_common::TimestampedValue<NodeType>(lower_bound_or_equal->timestamp, *node);
302 }
303 
304 template <typename NodeType>
305 std::vector<localization_common::Time> TimestampedCombinedNodes<NodeType>::Timestamps() const {
306  return timestamp_keys_map_.Timestamps();
307 }
308 
309 template <typename NodeType>
311  return timestamp_keys_map_.Duration();
312 }
313 
314 template <typename NodeType>
316  const localization_common::Time oldest_allowed_timestamp) const {
317  const auto old_values = timestamp_keys_map_.OldValues(oldest_allowed_timestamp);
318  std::vector<NodeType> old_nodes;
319  for (const auto& old_value : old_values) {
320  const auto old_node = Node(old_value);
321  if (!old_node) {
322  LogError("OldNodes: Failed to get node for keys.");
323  continue;
324  }
325  old_nodes.emplace_back(*old_node);
326  }
327  return old_nodes;
328 }
329 
330 template <typename NodeType>
332  const localization_common::Time oldest_allowed_timestamp) const {
333  const auto old_timestamp_key_sets = timestamp_keys_map_.OldValues(oldest_allowed_timestamp);
334  gtsam::KeyVector all_old_keys;
335  for (const auto& old_timestamp_key_set : old_timestamp_key_sets) {
336  const auto& old_keys = old_timestamp_key_set.value;
337  all_old_keys.insert(all_old_keys.end(), old_keys.begin(), old_keys.end());
338  }
339  return all_old_keys;
340 }
341 
342 template <typename NodeType>
344  const auto old_values = timestamp_keys_map_.OldValues(oldest_allowed_timestamp);
345  timestamp_keys_map_.RemoveOldValues(oldest_allowed_timestamp);
346  int num_removed_nodes = 0;
347  for (const auto& old_value : old_values)
348  if (Remove(old_value.value)) ++num_removed_nodes;
349  return num_removed_nodes;
350 }
351 
352 template <typename NodeType>
354  const localization_common::Time timestamp) const {
355  const auto closest = timestamp_keys_map_.Closest(timestamp);
356  if (!closest) return boost::none;
357  return Node(*closest);
358 }
359 
360 template <typename NodeType>
361 boost::optional<localization_common::Time> TimestampedCombinedNodes<NodeType>::ClosestTimestamp(
362  const localization_common::Time timestamp) const {
363  const auto closest = timestamp_keys_map_.Closest(timestamp);
364  if (!closest) return boost::none;
365  return closest->timestamp;
366 }
367 
368 template <typename NodeType>
370  return values_->gtsam_values();
371 }
372 
373 template <typename NodeType>
375  return timestamp_keys_map_.Contains(timestamp);
376 }
377 
378 template <typename NodeType>
379 template <class ARCHIVE>
380 void TimestampedCombinedNodes<NodeType>::serialize(ARCHIVE& ar, const unsigned int /*version*/) {
381  ar& BOOST_SERIALIZATION_NVP(values_);
382  ar& BOOST_SERIALIZATION_NVP(timestamp_keys_map_);
383 }
384 } // namespace nodes
385 
386 #endif // NODES_TIMESTAMPED_COMBINED_NODES_H_
nodes::TimestampedCombinedNodes::size
size_t size() const
Definition: timestamped_combined_nodes.h:223
nodes::TimestampedCombinedNodes::TimestampedCombinedNodes
TimestampedCombinedNodes()=default
nodes::TimestampedCombinedNodes::Duration
double Duration() const
Definition: timestamped_combined_nodes.h:310
nodes::TimestampedCombinedNodes::ClosestNode
boost::optional< NodeType > ClosestNode(const localization_common::Time timestamp) const
Definition: timestamped_combined_nodes.h:353
nodes::TimestampedCombinedNodes::Contains
bool Contains(const localization_common::Time timestamp) const
Definition: timestamped_combined_nodes.h:374
values.h
nodes::TimestampedCombinedNodes::LatestTimestamp
boost::optional< localization_common::Time > LatestTimestamp() const
Definition: timestamped_combined_nodes.h:247
nodes::TimestampedCombinedNodes::OldNodes
std::vector< NodeType > OldNodes(const localization_common::Time oldest_allowed_timestamp) const
Definition: timestamped_combined_nodes.h:315
nodes::TimestampedCombinedNodes::LowerAndUpperBoundTimestamps
std::pair< boost::optional< localization_common::Time >, boost::optional< localization_common::Time > > LowerAndUpperBoundTimestamps(const localization_common::Time timestamp) const
Definition: timestamped_combined_nodes.h:262
LogError
#define LogError(msg)
Definition: logger.h:55
nodes
Definition: combined_nav_state_nodes.h:24
nodes::TimestampedCombinedNodes::gtsam_values
const gtsam::Values & gtsam_values() const
Definition: timestamped_combined_nodes.h:369
nodes::TimestampedCombinedNodes::OldestTimestamp
boost::optional< localization_common::Time > OldestTimestamp() const
Definition: timestamped_combined_nodes.h:233
nodes::TimestampedCombinedNodes::~TimestampedCombinedNodes
virtual ~TimestampedCombinedNodes()=default
gpio::Value
Value
Definition: GPIO.h:42
nodes::TimestampedCombinedNodes::OldKeys
gtsam::KeyVector OldKeys(const localization_common::Time oldest_allowed_timestamp) const
Definition: timestamped_combined_nodes.h:331
nodes::TimestampedCombinedNodes::RemoveOldNodes
int RemoveOldNodes(const localization_common::Time oldest_allowed_timestamp)
Definition: timestamped_combined_nodes.h:343
timestamped_set.h
nodes::TimestampedCombinedNodes
Definition: timestamped_combined_nodes.h:44
localization_common::TimestampedSet< gtsam::KeyVector >
time.h
nodes::TimestampedCombinedNodes::Add
gtsam::KeyVector Add(const localization_common::Time timestamp, const NodeType &node)
Definition: timestamped_combined_nodes.h:174
nodes::TimestampedCombinedNodes::LowerAndUpperBoundNodes
std::pair< boost::optional< NodeType >, boost::optional< NodeType > > LowerAndUpperBoundNodes(const localization_common::Time timestamp) const
Definition: timestamped_combined_nodes.h:279
nodes::TimestampedCombinedNodes::Value
boost::optional< T > Value(const gtsam::Key &key) const
Definition: timestamped_combined_nodes.h:197
localization_common::TimestampedValue::timestamp
Time timestamp
Definition: timestamped_set.h:40
nodes::TimestampedCombinedNodes::Keys
gtsam::KeyVector Keys(const localization_common::Time timestamp) const
Definition: timestamped_combined_nodes.h:202
localization_common::TimestampedValue
Definition: timestamped_set.h:37
nodes::TimestampedCombinedNodes::ClosestTimestamp
boost::optional< localization_common::Time > ClosestTimestamp(const localization_common::Time timestamp) const
Definition: timestamped_combined_nodes.h:361
nodes::TimestampedCombinedNodes::Remove
bool Remove(const localization_common::Time &timestamp)
Definition: timestamped_combined_nodes.h:208
localization_common::TimestampedValue::value
T value
Definition: timestamped_set.h:42
nodes::TimestampedCombinedNodes::Node
boost::optional< NodeType > Node(const localization_common::Time timestamp) const
Definition: timestamped_combined_nodes.h:183
std
Definition: tensor.h:39
nodes::TimestampedCombinedNodes::LatestNode
boost::optional< NodeType > LatestNode() const
Definition: timestamped_combined_nodes.h:254
nodes::TimestampedCombinedNodes::Timestamps
std::vector< localization_common::Time > Timestamps() const
Definition: timestamped_combined_nodes.h:305
nodes::TimestampedCombinedNodes::empty
bool empty() const
Definition: timestamped_combined_nodes.h:228
nodes::TimestampedCombinedNodes::OldestNode
boost::optional< NodeType > OldestNode() const
Definition: timestamped_combined_nodes.h:240
localization_common::Time
double Time
Definition: time.h:23
nodes::TimestampedCombinedNodes::values_
std::shared_ptr< Values > values_
Definition: timestamped_combined_nodes.h:145
nodes::TimestampedCombinedNodes::LowerBoundOrEqual
boost::optional< localization_common::TimestampedValue< NodeType > > LowerBoundOrEqual(const localization_common::Time timestamp) const
Definition: timestamped_combined_nodes.h:295