OSVR Framework (Internal Development Docs)  0.6-1962-g59773924
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
TrackedBody.cpp
Go to the documentation of this file.
1 
11 // Copyright 2016 Sensics, Inc.
12 //
13 // Licensed under the Apache License, Version 2.0 (the "License");
14 // you may not use this file except in compliance with the License.
15 // You may obtain a copy of the License at
16 //
17 // http://www.apache.org/licenses/LICENSE-2.0
18 //
19 // Unless required by applicable law or agreed to in writing, software
20 // distributed under the License is distributed on an "AS IS" BASIS,
21 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 // See the License for the specific language governing permissions and
23 // limitations under the License.
24 
25 // Internal Includes
26 #include "TrackedBody.h"
27 #include "ApplyIMUToState.h"
28 #include "BodyTargetInterface.h"
29 #include "CannedIMUMeasurement.h"
30 #include "HistoryContainer.h"
31 #include "StateHistory.h"
32 #include "TrackedBodyIMU.h"
33 #include "TrackedBodyTarget.h"
34 #include "TrackingSystem.h"
35 
36 // Library/third-party includes
37 #include <boost/optional.hpp>
39 
40 #include <util/Stride.h>
41 
42 // Standard includes
43 #include <iostream>
44 
45 namespace osvr {
46 namespace vbtracker {
47  using BodyStateHistoryEntry = StateHistoryEntry<BodyState>;
48 
50 
51  HistoryContainer<BodyStateHistoryEntry> stateHistory;
52  HistoryContainer<CannedIMUMeasurement> imuMeasurements;
53  bool everHadPose = false;
54  };
56  : m_system(system), m_id(id), m_impl(new Impl) {
57  using StateVec = kalman::types::DimVector<BodyState>;
59  m_state.setErrorCovariance(StateVec::Constant(10).asDiagonal());
60 
61  m_processModel.setDamping(getParams().linearVelocityDecayCoefficient,
62  getParams().angularVelocityDecayCoefficient);
63  m_processModel.setNoiseAutocorrelation(
64  kalman::types::Vector<6>(getParams().processNoiseAutocorrelation));
65  }
66 
68 
70  TrackedBody::createIntegratedIMU(double orientationVariance,
71  double angularVelocityVariance) {
72  if (m_imu) {
73  // already have an IMU!
74  return nullptr;
75  }
76  m_imu.reset(new TrackedBodyIMU{*this, orientationVariance,
77  angularVelocityVariance});
78  return m_imu.get();
79  }
80 
81  TrackedBodyTarget *
82  TrackedBody::createTarget(Eigen::Vector3d const &targetToBody,
83  TargetSetupData const &setupData) {
84  if (m_target) {
85  // already have a target!
87  return nullptr;
88  }
90  m_target.reset(
91  new TrackedBodyTarget{*this, BodyTargetInterface{getState()},
92  targetToBody, setupData, TargetId{0}});
93  return m_target.get();
94  }
95 
97  return m_system.getParams();
98  }
99 
100  BodyId TrackedBody::getId() const { return m_id; }
102  return m_stateTime;
103  }
104 
106  osvr::util::time::TimeValue const &desiredTime,
107  osvr::util::time::TimeValue &outTime, BodyState &outState) {
108  auto it = m_impl->stateHistory.closest_not_newer(desiredTime);
109  if (m_impl->stateHistory.end() == it) {
111  return false;
112  }
113  outTime = it->first;
114  it->second.restore(outState);
115  return true;
116  }
117 
119  getOldestPossibleMeasurementSource(TrackedBody const &body,
120  OSVR_TimeValue const &videoTime) {
123  osvr::util::time::TimeValue oldest = videoTime;
124  if (body.hasIMU()) {
126  auto imuTimestamp = body.getIMU().getLastUpdate();
127  if (imuTimestamp < oldest) {
128  oldest = imuTimestamp;
129  }
130  }
131  return oldest;
132  }
133 
134  void TrackedBody::pruneHistory(OSVR_TimeValue const &videoTime) {
135 #if 0
136  static ::util::Stride s(100);
137  if (++s) {
138  std::cout << "stateHistory High water mark: "
139  << m_impl->stateHistory.highWaterMark() << std::endl;
140  std::cout << "imuMeasurements High water mark: "
141  << m_impl->imuMeasurements.highWaterMark() << std::endl;
142  }
143 #endif
144 
145  if (m_impl->stateHistory.empty()) {
146  // can't prune an empty structure
147  return;
148  }
149  auto oldest = getOldestPossibleMeasurementSource(*this, videoTime);
150 
151  if (m_impl->stateHistory.newest_timestamp() < oldest) {
152  // It would be a strange set of circumstances to bring this about,
153  // but we don't want to go from a non-empty history to an empty one.
154  // So in this case, we want to make sure we have at least one entry
155  // left over in the state history. Here's a quick way of doing that.
156  oldest = m_impl->stateHistory.newest_timestamp();
157  }
158 
159  m_impl->stateHistory.pop_before(oldest);
160 
161  m_impl->imuMeasurements.pop_before(oldest);
162  }
163 
165  osvr::util::time::TimeValue const &origTime,
166  osvr::util::time::TimeValue const &newTime, BodyState const &newState) {
167 #if !(defined(OSVR_UVBI_ASSUME_SINGLE_CAMERA) && \
168  defined(OSVR_UVBI_ASSUME_CAMERA_ALWAYS_SLOWER))
169 #error "Current code assumes that all we have to replay is IMU measurements."
170 #endif // !(defined(OSVR_UVBI_ASSUME_SINGLE_CAMERA) &&
171  // defined(OSVR_UVBI_ASSUME_CAMERA_ALWAYS_SLOWER))
172 
174  auto numPopped = m_impl->stateHistory.pop_after(origTime);
177 
179  m_state = newState;
180  m_stateTime = newTime;
181  if (m_impl->stateHistory.is_valid_to_push_newest(m_stateTime)) {
182  pushState();
183  }
184 
186  auto numReplayed = std::size_t{0};
187  for (auto &imuHist :
188  m_impl->imuMeasurements.get_range_newer_than(newTime)) {
189  applyIMUMeasurement(imuHist.first, imuHist.second);
190  ++numReplayed;
191  }
192  }
193 
194  void TrackedBody::pushState() {
195  m_impl->stateHistory.push_newest(m_stateTime,
196  BodyStateHistoryEntry{m_state});
197  }
198 
200  util::time::TimeValue const &tv, CannedIMUMeasurement const &meas) {
201  if (!getSystem().isRoomCalibrationComplete()) {
205  if (meas.orientationValid()) {
206  Eigen::Quaterniond quat;
207  meas.restoreQuat(quat);
208  getSystem().calibrationHandleIMUData(getId(), tv, quat);
209  }
210  return;
211  }
212 
213  if (!m_impl->imuMeasurements.is_valid_to_push_newest(tv)) {
214  // This one is out of order from the IMU!
216  throw std::runtime_error("Got out of order timestamps from IMU!");
217  }
218 
223  if (hasEverHadPoseEstimate()) {
224  applyIMUMeasurement(tv, meas);
225  }
226 
227  m_impl->imuMeasurements.push_newest(tv, meas);
228  }
229 
230  void TrackedBody::applyIMUMeasurement(util::time::TimeValue const &tv,
231  CannedIMUMeasurement const &meas) {
232  // Only apply and push new stuff
233  if (m_impl->stateHistory.is_valid_to_push_newest(tv)) {
234  applyIMUToState(getSystem(), m_stateTime, m_state, m_processModel,
235  tv, meas);
236  m_stateTime = tv;
237  pushState();
238  }
239  }
240 
243  auto ret = false;
244  forEachTarget([&ret](TrackedBodyTarget &target) {
245  ret = ret || target.hasPoseEstimate();
246  });
247  return ret;
248  }
249 
250  bool TrackedBody::hasEverHadPoseEstimate() const {
251  if (m_impl->everHadPose) {
252  return true;
253  }
254  auto ret = false;
255  forEachTarget([&ret](TrackedBodyTarget &target) {
256  ret = ret || target.hasPoseEstimate();
257  });
258  m_impl->everHadPose = ret;
259 
260  return ret;
261  }
262 
263 } // namespace vbtracker
264 } // namespace osvr
Eigen::Matrix< Scalar, n, 1 > Vector
A vector of length n.
osvr::util::time::TimeValue getStateTime() const
Get timestamp associated with current state.
bool hasPoseEstimate() const
Do we have a pose estimate for this body in general?
A way for targets to access internals of a tracked body.
TrackedBody(TrackingSystem &system, BodyId id)
Constructor.
Definition: TrackedBody.cpp:55
Vector< Dimension< T >::value > DimVector
A vector of length = dimension of T.
void setDamping(double posDamping, double oriDamping)
Set the damping - must be in (0, 1)
void pruneHistory(OSVR_TimeValue const &videoTime)
BodyId getId() const
Gets the body ID within the tracking system.
void replaceStateSnapshot(osvr::util::time::TimeValue const &origTime, osvr::util::time::TimeValue const &newTime, BodyState const &newState)
TrackedBodyIMU & getIMU()
Get the IMU - only valid if hasIMU is true.
Definition: TrackedBody.h:113
TrackedBodyTarget * createTarget(Eigen::Vector3d const &targetToBody, TargetSetupData const &setupData)
Definition: TrackedBody.cpp:82
ConfigParams const & getParams() const
ConfigParams const & getParams() const
Definition: TrackedBody.cpp:96
General configuration parameters.
Definition: ConfigParams.h:82
~TrackedBody()
Destructor - explicit so we can use unique_ptr for our pimpls.
Definition: TrackedBody.cpp:67
Standardized, portable parallel to struct timeval for representing both absolute times and time inter...
Definition: TimeValueC.h:81
bool hasIMU() const
Does this tracked body have an IMU?
Definition: TrackedBody.h:110
void calibrationHandleIMUData(BodyId id, util::time::TimeValue const &tv, Eigen::Quaterniond const &quat)
bool getStateAtOrBefore(osvr::util::time::TimeValue const &desiredTime, osvr::util::time::TimeValue &outTime, BodyState &outState)
void incorporateNewMeasurementFromIMU(util::time::TimeValue const &tv, CannedIMUMeasurement const &meas)