Main MRPT website > C++ reference
MRPT logo
add-observations.h
Go to the documentation of this file.
1 /* +---------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2015, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +---------------------------------------------------------------------------+ */
9 
10 #pragma once
11 
12 namespace mrpt { namespace srba {
13 
14 #define OBS_SUPER_VERBOSE 0
15 
16 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
18  const TKeyFrameID observing_kf_id,
19  const typename observation_traits<OBS_TYPE>::observation_t & new_obs,
20  const array_landmark_t * fixed_relative_position,
21  const array_landmark_t * unknown_relative_position_init_val
22  )
23 {
24  m_profiler.enter("add_observation");
25 
26  ASSERT_( !( fixed_relative_position!=NULL && unknown_relative_position_init_val!=NULL) ) // Both can't be !=NULL at once.
27 
28  const bool is_1st_time_seen = ( new_obs.feat_id>=rba_state.all_lms.size() || rba_state.all_lms[new_obs.feat_id].rfp==NULL );
29 
30  const bool is_fixed =
31  // This is the first observation of a fixed landmark:
32  (fixed_relative_position!=NULL)
33  || // or if it was observed before, get its feature type from stored structure:
34  (!is_1st_time_seen && rba_state.all_lms[new_obs.feat_id].has_known_pos );
35 
36  // Append all new observation to raw vector:
37  // ---------------------------------------------------------------------
38  const size_t new_obs_idx = rba_state.all_observations.size(); // O(1)
39 
40 #ifdef SRBA_WORKAROUND_MSVC9_DEQUE_BUG
41  rba_state.all_observations.push_back(stlplus::smart_ptr<k2f_edge_t>(new k2f_edge_t)); // Create new k2f_edge -- O(1)
42 #else
43  rba_state.all_observations.push_back(k2f_edge_t()); // Create new k2f_edge -- O(1)
44 #endif
45 
46  rba_state.all_observations_Jacob_validity.push_back(1); // Also grow this vector (its content now are irrelevant, they'll be updated in optimization)
47  char * const jacob_valid_bit = &(*rba_state.all_observations_Jacob_validity.rbegin());
48 
49  // Get a ref. to observation info, filled in below:
50 #ifdef SRBA_WORKAROUND_MSVC9_DEQUE_BUG
51  k2f_edge_t & new_k2f_edge = *(*rba_state.all_observations.rbegin());
52 #else
53  k2f_edge_t & new_k2f_edge = *rba_state.all_observations.rbegin();
54 #endif
55 
56  // New landmark? Update LMs structures if this is the 1st time we see this landmark:
57  // -----------------------------------------------------------------------
58  if (is_1st_time_seen)
59  {
60  if (is_fixed)
61  { // LM with KNOWN relative position.
62  // ----------------------------------
63  TRelativeLandmarkPos new_rfp;
64  new_rfp.id_frame_base = observing_kf_id; // The current KF at creation time becomes the relative coordinate base.
65  new_rfp.pos = *fixed_relative_position;
66 
67  // O(1) insertion if the obs.feat_id is the largest until now:
68  typename TRelativeLandmarkPosMap::iterator it_new = rba_state.known_lms.insert(
69  rba_state.known_lms.end(),
70  typename TRelativeLandmarkPosMap::value_type(new_obs.feat_id, new_rfp )
71  );
72 
73  // Add to list of all LMs: Amortized O(1)
74  if (new_obs.feat_id >= rba_state.all_lms.size()) rba_state.all_lms.resize(new_obs.feat_id+1);
75  rba_state.all_lms[new_obs.feat_id] = typename landmark_traits<LM_TYPE>::TLandmarkEntry(true /*known pos.*/, &it_new->second);
76  }
77  else
78  { // LM with UNKNOWN relative position.
79  // ----------------------------------
80  // O(1) insertion if the feat_ID is the largest until now:
81 
82  TRelativeLandmarkPos new_rfp;
83  new_rfp.id_frame_base = observing_kf_id; // The current KF at creation time becomes the relative coordinate base.
84  if (unknown_relative_position_init_val)
85  new_rfp.pos = *unknown_relative_position_init_val;
86  else {
87  // Default landmark position: Invoke sensor's inverse model.
88  sensor_model_t::inverse_sensor_model(new_rfp.pos,new_obs.obs_data,this->parameters.sensor);
89 
90  // Take into account the sensor pose wrt the KF:
91  RBA_OPTIONS::sensor_pose_on_robot_t::template sensor2robot_point<LM_TYPE>(new_rfp.pos, this->parameters.sensor_pose );
92  }
93 
94  typename TRelativeLandmarkPosMap::iterator it_new = rba_state.unknown_lms.insert(
95  rba_state.unknown_lms.end(),
96  typename TRelativeLandmarkPosMap::value_type( new_obs.feat_id, new_rfp )
97  );
98 
99  // Add to list of all LMs:
100  if (new_obs.feat_id >= rba_state.all_lms.size()) rba_state.all_lms.resize(new_obs.feat_id+1);
101  rba_state.all_lms[new_obs.feat_id] = typename landmark_traits<LM_TYPE>::TLandmarkEntry(false /*unknown pos.*/, &it_new->second);
102 
103  // Expand Jacobian dh_df to accomodate a new column for a new unknown:
104  // ("Remap indices" in dh_df for each column are the feature IDs of those feature with unknown positions)
105  rba_state.lin_system.dh_df.appendCol( new_obs.feat_id );
106  }
107  }
108 
109  // Maintain a pointer to the relative position wrt its base keyframe:
110  TRelativeLandmarkPos *lm_rel_pos = rba_state.all_lms[new_obs.feat_id].rfp;
111  // and get the ID of the base keyframe for the observed landmark:
112  const TKeyFrameID base_id = lm_rel_pos->id_frame_base;
113 
114  // Fill in kf-to-feature edge data:
115  // ------------------------------------
116  new_k2f_edge.obs.kf_id = observing_kf_id;
117  new_k2f_edge.obs.obs = new_obs;
118  new_k2f_edge.obs.obs.obs_data.getAsArray(new_k2f_edge.obs.obs_arr); // Save the observation data as an array now, only once, and reuse it from now on in optimizations, etc.
119  new_k2f_edge.is_first_obs_of_unknown = is_1st_time_seen && !is_fixed;
120  new_k2f_edge.feat_has_known_rel_pos = is_fixed;
121  new_k2f_edge.feat_rel_pos = lm_rel_pos;
122 
123 
124  // Update keyframe incident edge list:
125  // ---------------------------------------------------------------------
126  ASSERTDEB_( observing_kf_id < rba_state.keyframes.size() )
127 
128  keyframe_info &kf_info = rba_state.keyframes[ observing_kf_id ]; // O(1)
129 
130  // Incident edges:
131  kf_info.adjacent_k2f_edges.push_back( &new_k2f_edge ); // Amortized O(1)
132 
133 
134  // Update linear system:
135 
136  // If the observed feat has a known rel. pos., only dh_dAp; otherwise, both dh_dAp and dh_df
137  // ---------------------------------------------------------------------
138  // Add a new (block) row for this new observation (row index = "new_obs_idx" defined above)
139  // We must create a block for each edge in between the observing and the ref. base id.
140  // Note: no error checking here in find's for efficiency...
141  m_profiler.enter("add_observation.jacobs.sym");
142 
143  // ===========================
144  // Jacob 1/2: dh_dAp
145  // ===========================
146  bool graph_says_ignore_this_obs = false;
147 
148  if (base_id!=new_k2f_edge.obs.kf_id) // If this is a feat with unknown rel.pos. and it's its first observation, the dh_dAp part of the Jacobian is empty.
149  {
150 #if OBS_SUPER_VERBOSE
151  std::cout << "Jacobian dh_dAp for obs #"<<new_obs_idx << " has these edges [obs_kf="<<observing_kf_id<< " base_kf="<< base_id<<"]:\n";
152 #endif
153 
154  // Since "all_edges" is symmetric, only the (i,j), i>j entries are stored:
155  const TKeyFrameID from = std::max(observing_kf_id, base_id);
156  const TKeyFrameID to = std::min(observing_kf_id, base_id);
157 
158  const bool all_edges_inverse = (from!=observing_kf_id);
159 
160  typename rba_problem_state_t::TSpanningTree::all_edges_maps_t::const_iterator it_map = rba_state.spanning_tree.sym.all_edges.find(from); // Was: observing
161  ASSERTMSG_(it_map != rba_state.spanning_tree.sym.all_edges.end(), mrpt::format("No ST.all_edges found for observing_id=%u, base_id=%u", static_cast<unsigned int>(observing_kf_id), static_cast<unsigned int>(base_id) ) )
162 
164  //ASSERTMSG_(it_obs_ed != it_map->second.end(), mrpt::format("No spanning-tree found from KF #%u to KF #%u, base of observation of landmark #%u", static_cast<unsigned int>(observing_kf_id),static_cast<unsigned int>(base_id),static_cast<unsigned int>(new_obs.feat_id) ))
165 
166  if (it_obs_ed != it_map->second.end())
167  {
168  const typename rba_problem_state_t::k2k_edge_vector_t & obs_edges = it_obs_ed->second;
169  ASSERT_(!obs_edges.empty())
170 
171  TKeyFrameID curKF = observing_kf_id; // The backward running index towards "base_id"
172  for (size_t j=0;j<obs_edges.size();j++)
173  {
174  const size_t i = all_edges_inverse ? (obs_edges.size()-j-1) : j;
175 
176  ASSERT_(curKF!=to)
177 
178  const size_t edge_id = obs_edges[i]->id;
179 
180  // Normal direction: from -> to, so "to"=="curKF" (we go backwards)
181  const bool normal_dir = (obs_edges[i]->to==curKF);
182 
183 #if OBS_SUPER_VERBOSE
184  std::cout << " * edge #"<<edge_id<< ": "<<obs_edges[i]->from <<" => "<<obs_edges[i]->to << " (inverse: " << (normal_dir ? "no":"yes") << ")\n";
185 #endif
186 
187  // Get sparse block column:
188  typename TSparseBlocksJacobians_dh_dAp::col_t & col = rba_state.lin_system.dh_dAp.getCol(edge_id);
189 
190  // Create new entry: O(1) optimized insert if obs_idx is the largest index (as it will normally be):
191  typename TSparseBlocksJacobians_dh_dAp::col_t::iterator it_new_entry = col.insert(
192  col.end(),
193  typename TSparseBlocksJacobians_dh_dAp::col_t::value_type( new_obs_idx, typename TSparseBlocksJacobians_dh_dAp::TEntry() )
194  );
195 
196  typename TSparseBlocksJacobians_dh_dAp::TEntry & entry = it_new_entry->second;
197 
198  entry.sym.obs_idx = new_obs_idx;
199  entry.sym.is_valid = jacob_valid_bit;
200  entry.sym.edge_normal_dir = normal_dir;
201  entry.sym.kf_d = curKF;
202  entry.sym.kf_base = base_id;
203  entry.sym.feat_rel_pos = lm_rel_pos;
204  entry.sym.k2k_edge_id = edge_id;
205  //entry.sym.rel_poses_path = &obs_edges; // Path OBSERVING_KF -> BASE_KF
206 
207  // Pointers to placeholders of future numeric results of the spanning tree:
208  entry.sym.rel_pose_base_from_d1 = & rba_state.spanning_tree.num[curKF][base_id];
209  entry.sym.rel_pose_d1_from_obs =
210  (curKF==observing_kf_id) ?
211  NULL // Use special value "NULL" when the CPose is fixed to the origin.
212  :
213  & rba_state.spanning_tree.num[observing_kf_id][curKF];
214 
215  // next node after this edge is:
216  curKF = normal_dir ? obs_edges[i]->from : obs_edges[i]->to;
217  }
218  }
219  else
220  {
221  // Ignore this obs...
222  graph_says_ignore_this_obs=true;
223  }
224  }
225 
226  // ===========================
227  // Jacob 2/2: dh_df
228  // ===========================
229  if (!is_fixed && !graph_says_ignore_this_obs) // Only for features with unknown rel.pos.
230  {
231  // "Remap indices" in dh_df for each column are the feature IDs of those feature with unknown positions.
232  const size_t remapIdx = new_k2f_edge.obs.obs.feat_id;
233 
234  const mrpt::utils::map_as_vector<size_t,size_t> &dh_df_remap = rba_state.lin_system.dh_df.getColInverseRemappedIndices();
235  const mrpt::utils::map_as_vector<size_t,size_t>::const_iterator it_idx = dh_df_remap.find(remapIdx); // O(1) in mrpt::utils::map_as_vector()
236  ASSERT_(it_idx!=dh_df_remap.end())
237 
238  const size_t col_idx = it_idx->second;
239 
241  cout << "dh_df: col_idx=" << col_idx << " feat_id=" << remapIdx << " obs_idx=" << new_obs_idx << endl;
242 #endif
243  // Get sparse block column:
244  typename TSparseBlocksJacobians_dh_df::col_t & col = rba_state.lin_system.dh_df.getCol(col_idx);
245 
246  // Create new entry: O(1) optimized insert if obs_idx is the largest index (as it will normally be):
247  typename TSparseBlocksJacobians_dh_df::col_t::iterator it_new_entry = col.insert(
248  col.end(),
249  typename TSparseBlocksJacobians_dh_df::col_t::value_type( new_obs_idx, typename TSparseBlocksJacobians_dh_df::TEntry() )
250  );
251 
252  typename TSparseBlocksJacobians_dh_df::TEntry & entry = it_new_entry->second;
253 
254  entry.sym.obs_idx = new_obs_idx;
255  entry.sym.is_valid = jacob_valid_bit;
256 
257  // Pointer to relative position:
258  entry.sym.feat_rel_pos = lm_rel_pos;
259 
260  // Pointers to placeholders of future numeric results of the spanning tree:
261  entry.sym.rel_pose_base_from_obs =
262  (new_k2f_edge.is_first_obs_of_unknown) ?
263  NULL // Use special value "NULL" when the CPose is fixed to the origin.
264  :
265  & rba_state.spanning_tree.num[observing_kf_id][base_id];
266  }
267 
268  m_profiler.leave("add_observation.jacobs.sym");
269 
270  m_profiler.leave("add_observation");
271 
272  return new_obs_idx;
273 }
274 
275 } } // end NS
obs_traits_t::observation_t obs
Observation data.
Definition: srba_types.h:433
OBS_TRAITS::obs_data_t obs_data
Observed data.
Definition: srba_types.h:151
vec_t::const_iterator const_iterator
Definition: map_as_vector.h:56
kf2kf_pose_traits< KF2KF_POSE_TYPE >::k2k_edge_vector_t k2k_edge_vector_t
Definition: srba_types.h:478
iterator find(const size_t i)
Constant-time find, returning an iterator to the pair or to end() if not found (that is...
Scalar * iterator
Definition: eigen_plugins.h:23
const Scalar * const_iterator
Definition: eigen_plugins.h:24
lm_traits_t::TRelativeLandmarkPos * feat_rel_pos
Pointer to the known/unknown rel.pos. (always!=NULL)
Definition: srba_types.h:447
obs_traits_t::array_obs_t obs_arr
Observation data, summarized as an array of its parameters: obs.obs_data.getAsArray(obs_arr);.
Definition: srba_types.h:434
bool is_first_obs_of_unknown
true if this is the first observation of a feature with unknown relative position ...
Definition: srba_types.h:446
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
landmark_traits_t::TRelativeLandmarkPos TRelativeLandmarkPos
One landmark position (relative to its base KF)
Definition: RbaEngine.h:98
#define OBS_SUPER_VERBOSE
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
#define ASSERTDEB_(f)
Defines an assertion mechanism - only when compiled in debug.
The argument "LM_TRAITS" can be any of those defined in srba/models/landmarks.h (typically, either landmarks::Euclidean3D or landmarks::Euclidean2D).
Definition: srba_types.h:100
#define ASSERT_(f)
Information per key-frame needed for RBA.
Definition: srba_types.h:453
Keyframe-to-feature edge: observation data stored for each keyframe.
Definition: srba_types.h:442
#define ASSERTMSG_(f, __ERROR_MSG)
size_t add_observation(const TKeyFrameID observing_kf_id, const typename observation_traits_t::observation_t &new_obs, const array_landmark_t *fixed_relative_position=NULL, const array_landmark_t *unknown_relative_position_init_val=NULL)
Creates a new known/unknown position landmark (upon first LM observation ), and expands Jacobians wit...
bool feat_has_known_rel_pos
whether it's a known or unknown relative position feature
Definition: srba_types.h:445
uint64_t TKeyFrameID
Numeric IDs for key-frames (KFs)
Definition: srba_types.h:31



Page generated by Doxygen 1.8.9.1 for MRPT 1.3.0 SVN: at Sun Sep 13 03:55:12 UTC 2015