OSVR Framework (Internal Development Docs)  0.6-1962-g59773924
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
TrackedBodyTarget.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 "TrackedBodyTarget.h"
28 #include "BodyTargetInterface.h"
29 #include "HDKLedIdentifier.h"
30 #include "LED.h"
31 #include "PoseEstimatorTypes.h"
32 #include "PoseEstimator_RANSAC.h"
35 #include "TrackedBody.h"
36 #include "cvToEigen.h"
37 #include <osvr/Util/CSV.h>
38 #include <osvr/Util/CSVCellGroup.h>
39 
40 // Library/third-party includes
41 #include <boost/assert.hpp>
42 #include <util/Stride.h>
43 
44 // Standard includes
45 #include <algorithm>
46 #include <fstream>
47 #include <iostream>
48 
49 #undef OSVR_DEBUG_ERROR_VARIANCE_WHEN_TRACKING_LOST
50 #undef OSVR_DEBUG_ERROR_VARIANCE
51 
52 #undef OSVR_UVBI_FRAMEDROP_HEURISTIC_WARNING
53 
54 #define OSVR_VERBOSE_ERROR_BOUNDS
55 
57 #undef OSVR_UVBI_DUMP_BLOB_CSV
58 
59 namespace osvr {
60 namespace vbtracker {
61  enum class TargetTrackingState {
62  RANSAC,
63  RANSACKalman,
64  EnteringKalman,
65  Kalman,
66  RANSACWhenBlobDetected,
67  RANSACKalmanWhenBlobDetected
68  };
69 
70  enum class TargetHealthState {
71  OK,
72  StopTrackingErrorBoundsExceeded,
73  StopTrackingLostSight,
74  HardResetNonFiniteState
75  };
76 
77  static const auto MAX_FRAMES_WITHOUT_BEACONS = 150;
78 
79  inline double getLimitOnMaxPositionalErrorVariance(double distance) {
84 
88  static const double A = 6.4116155459;
89  static const double B = 8e-5;
90  return B * std::exp(A * distance);
91  }
92 
93  inline double getMaxPositionalErrorVariance(BodyState const &bodyState) {
94  return bodyState.errorCovariance().diagonal().head<3>().maxCoeff();
95  }
96 
99  inline bool isStateSCAAT(TargetTrackingState trackingState) {
100  return !(trackingState == TargetTrackingState::RANSAC ||
101  trackingState == TargetTrackingState::RANSACKalman);
102  }
103 
105  public:
106  TargetHealthState operator()(BodyState const &bodyState,
107  LedPtrList const &leds,
108  TargetTrackingState trackingState) {
109  if (!bodyState.stateVector().array().allFinite()) {
110  return TargetHealthState::HardResetNonFiniteState;
111  }
112  if (!bodyState.getQuaternion().coeffs().array().allFinite()) {
113  return TargetHealthState::HardResetNonFiniteState;
114  }
115  if (leds.empty()) {
116  m_framesWithoutValidBeacons++;
117  } else {
118  m_framesWithoutValidBeacons = 0;
119  }
120 
121  if (isStateSCAAT(trackingState) &&
122  m_framesWithoutValidBeacons != 0) {
123  auto maxPositionalError =
124  getMaxPositionalErrorVariance(bodyState);
125  auto distance = bodyState.position().z();
126  auto errorLimit =
127  getLimitOnMaxPositionalErrorVariance(distance);
128  if (maxPositionalError > errorLimit) {
129  return TargetHealthState::StopTrackingErrorBoundsExceeded;
130  }
131  }
132 
133  if (m_framesWithoutValidBeacons > MAX_FRAMES_WITHOUT_BEACONS) {
134  return TargetHealthState::StopTrackingLostSight;
135  }
136  return TargetHealthState::OK;
137  }
138 
139  private:
140  std::size_t m_framesWithoutValidBeacons = 0;
141  };
142 
144  Impl(ConfigParams const &params, BodyTargetInterface const &bodyIface)
145  : bodyInterface(bodyIface), kalmanEstimator(params),
146  ransacKalmanEstimator(params.softResetPositionVarianceScale,
149 
150 #ifdef OSVR_UVBI_DUMP_BLOB_CSV
151  ,
152  blobFile("blobs.csv"), csv(blobFile)
153 #endif // OSVR_UVBI_DUMP_BLOB_CSV
154  {
155  }
156  BodyTargetInterface bodyInterface;
157  LedGroup leds;
158  LedPtrList usableLeds;
159  LedIdentifierPtr identifier;
160  RANSACPoseEstimator ransacEstimator;
161  SCAATKalmanPoseEstimator kalmanEstimator;
162  RANSACKalmanPoseEstimator ransacKalmanEstimator;
163 
164  TargetHealthEvaluator healthEval;
165 
166  TargetTrackingState trackingState = TargetTrackingState::RANSAC;
167  TargetTrackingState lastFrameAlgorithm = TargetTrackingState::RANSAC;
168 
170  bool permitKalman = true;
171 
174  const bool softResets = false;
175 
176  bool hasPrev = false;
177  osvr::util::time::TimeValue lastEstimate;
178 
181  std::size_t trackingResets = 0;
182  std::ostringstream outputSink;
183 
184 #ifdef OSVR_UVBI_DUMP_BLOB_CSV
185  std::ofstream blobFile;
186  util::StreamCSV csv;
187 #endif // OSVR_UVBI_DUMP_BLOB_CSV
188  };
189 
190  inline BeaconStateVec createBeaconStateVec(ConfigParams const &params,
191  TargetSetupData const &setupData,
192  Eigen::Vector3d &beaconOffset) {
193  {
195  if (params.offsetToCentroid) {
196  Eigen::Vector3d beaconSum = Eigen::Vector3d::Zero();
197  auto bNum = size_t{0};
198  for (auto &beacon : setupData.locations) {
199  beaconSum += cvToVector(beacon).cast<double>();
200  bNum++;
201  }
202  beaconOffset = beaconSum / bNum;
203  if (params.debug) {
204  std::cout << "[Tracker Target] Computed beacon centroid: "
205  << beaconOffset.transpose() << std::endl;
206  }
207  } else {
208  beaconOffset = Eigen::Vector3d::Map(params.manualBeaconOffset);
209  }
210  }
213  using size_type = TargetSetupData::size_type;
214  const auto n = setupData.numBeacons();
215  BeaconStateVec beacons;
216  beacons.reserve(n);
217  Eigen::Vector3d location;
218  for (size_type i = 0; i < n; ++i) {
219  location = cvToVector(setupData.locations[i]).cast<double>() -
220  beaconOffset;
221  BeaconStatePtr beacon(new BeaconState(
222  location, Eigen::Vector3d::Constant(
223  setupData.initialAutocalibrationErrors[i])
224  .asDiagonal()));
225  beacons.emplace_back(std::move(beacon));
226  }
227  return beacons;
228  }
229 
231  BodyTargetInterface const &bodyIface,
232  Eigen::Vector3d const &targetToBody,
233  TargetSetupData const &setupData,
234  TargetId id)
235  : m_body(body), m_id(id), m_targetToBody(targetToBody),
236  m_numBeacons(setupData.numBeacons()),
237  m_beaconMeasurementVariance(setupData.baseMeasurementVariances),
238  m_beaconFixed(setupData.isFixed),
239  m_beaconEmissionDirection(setupData.emissionDirections),
240  m_impl(new Impl(getParams(), bodyIface)) {
241 
243  m_beacons =
244  createBeaconStateVec(getParams(), setupData, m_beaconOffset);
245 
247  for (auto &beacon : m_beacons) {
248  m_origBeacons.emplace_back(new BeaconState(*beacon));
249  }
250 
252  m_beaconDebugData.resize(m_beacons.size());
253 
254 #ifdef OSVR_UVBI_DUMP_BLOB_CSV
255  {
258  for (std::size_t i = 0; i < m_numBeacons; ++i) {
259  auto prefix = std::to_string(i + 1) + ".";
260  m_impl->csv.getColumn(prefix + "x");
261  m_impl->csv.getColumn(prefix + "y");
262  m_impl->csv.getColumn(prefix + "diameter");
263  m_impl->csv.getColumn(prefix + "area");
264  m_impl->csv.getColumn(prefix + "bright");
265  }
266  m_impl->csv.startOutput();
267  }
268 #endif // OSVR_UVBI_DUMP_BLOB_CSV
269  {
271  std::unique_ptr<OsvrHdkLedIdentifier> identifier(
272  new OsvrHdkLedIdentifier(setupData.patterns));
273  m_impl->identifier = std::move(identifier);
274  }
275  m_verifyInvariants();
276  }
277 
278  TrackedBodyTarget::~TrackedBodyTarget() {}
279 
280  BodyTargetId TrackedBodyTarget::getQualifiedId() const {
281  return BodyTargetId(getBody().getId(), getId());
282  }
283 
284  Eigen::Vector3d
286  BOOST_ASSERT(!i.empty());
287  BOOST_ASSERT_MSG(i.value() < getNumBeacons(),
288  "Beacon ID must be less than number of beacons.");
289  BOOST_ASSERT_MSG(i.value() >= 0,
290  "Beacon ID must not be a sentinel value!");
291  return m_beacons.at(i.value())->stateVector() + m_beaconOffset;
292  }
293 
294  Eigen::Vector3d
296  BOOST_ASSERT(!i.empty());
297  BOOST_ASSERT_MSG(i.value() < getNumBeacons(),
298  "Beacon ID must be less than number of beacons.");
299  BOOST_ASSERT_MSG(i.value() >= 0,
300  "Beacon ID must not be a sentinel value!");
301  return m_beacons.at(i.value())->errorCovariance().diagonal();
302  }
303 
305  m_beacons.clear();
306  for (auto &beacon : m_origBeacons) {
307  m_beacons.emplace_back(new BeaconState(*beacon));
308  }
309  }
310 
312  LedMeasurementVec const &undistortedLeds) {
313  // std::list<LedMeasurement> measurements{begin(undistortedLeds),
314  // end(undistortedLeds)};
315  LedMeasurementVec measurements{undistortedLeds};
316  const auto prevUsableLedCount = usableLeds().size();
319  usableLeds().clear();
320 
321  if (getParams().streamBeaconDebugInfo) {
324  for (auto &data : m_beaconDebugData) {
325  data.reset();
326  }
327  }
328 
329  const auto blobMoveThreshold = getParams().blobMoveThreshold;
330  const auto blobsKeepIdentity = getParams().blobsKeepIdentity;
331  auto &myLeds = m_impl->leds;
332 
333  const auto prevLedCount = myLeds.size();
334 
335  const auto numMeasurements = measurements.size();
336 
337  AssignMeasurementsToLeds assignment(myLeds, undistortedLeds,
338  m_numBeacons, blobMoveThreshold);
339 
340  assignment.populateStructures();
341  static const auto HEAP_PREFIX = "[ASSIGN HEAP] ";
342  bool verbose = false;
343  if (getParams().extraVerbose) {
344  // if (getParams().debug) {
345  static ::util::Stride assignStride(157);
346  assignStride++;
347  if (assignStride) {
348  verbose = true;
349  }
350  }
351  if (verbose) {
352  std::cout << HEAP_PREFIX << "Heap contains " << assignment.size()
353  << " elts, of possible "
354  << assignment.theoreticalMaxSize() << " (ratio "
355  << assignment.heapSizeFraction() << ")" << std::endl;
356  }
357  while (assignment.hasMoreMatches()) {
358  auto ledAndMeasurement = assignment.getMatch();
359  auto &led = ledAndMeasurement.first;
360  auto &meas = ledAndMeasurement.second;
361  led.addMeasurement(meas, blobsKeepIdentity);
362  if (handleOutOfRangeIds(led, m_numBeacons)) {
367  auto success = assignment.resumbitMeasurement(meas);
368  std::cerr << "ERROR: We just got a faulty one: filtering in "
369  "measurement from "
370  << meas.loc
371  << " made an LED go invalid. The measurement "
372  << (success ? "could" : "could NOT")
373  << " be resubmitted successfully\n";
374  }
375  }
376  if (verbose) {
377  const auto numUnclaimedLedObjects =
378  assignment.numUnclaimedLedObjects();
379  const auto numUnclaimedMeasurements =
380  assignment.numUnclaimedMeasurements();
381  const auto usedMeasurements =
382  numMeasurements - numUnclaimedMeasurements;
383  if (usedMeasurements != assignment.numCompletedMatches()) {
384  std::cout
385  << HEAP_PREFIX
386  << "Error: numMeasurements - numUnclaimedMeasurements = "
387  << usedMeasurements << " but object reports "
388  << assignment.numCompletedMatches() << " matches!\n";
389  }
390  std::cout
391  << HEAP_PREFIX
392  << "Matched: " << assignment.numCompletedMatches()
393  << "\tUnclaimed Meas: " << assignment.numUnclaimedMeasurements()
394  << "\tUnclaimed LED: " << assignment.numUnclaimedLedObjects()
396  << "\tRemaining: " << assignment.size() << "\n";
397  }
398 
399  assignment.eraseUnclaimedLedObjects(verbose);
400 
401  // If we have any blobs that have not been associated with an
402  // LED, then we add a new LED for each of them.
403  // std::cout << "Had " << Leds.size() << " LEDs, " <<
404  // keyPoints.size() << " new ones available" << std::endl;
405  assignment.forEachUnclaimedMeasurement([&](LedMeasurement const &meas) {
406  myLeds.emplace_back(m_impl->identifier.get(), meas);
407  });
408 
411  updateUsableLeds();
412 
413 #ifdef OSVR_UVBI_DUMP_BLOB_CSV
414  {
415  static bool first = true;
416  if (first) {
417  first = false;
418  std::cout << "Dumping first row of blob data." << std::endl;
419  }
420  auto &row = m_impl->csv.row();
421  for (auto &led : usableLeds()) {
422  auto prefix =
423  std::to_string(led->getOneBasedID().value()) + ".";
424  row << util::cellGroup(
425  prefix, cvToVector(led->getLocationForTracking()))
426  << util::cell(prefix + "diameter",
427  led->getMeasurement().diameter)
428  << util::cell(prefix + "area", led->getMeasurement().area)
429  << util::cell(prefix + "bright", led->isBright());
430  }
431  }
432 #endif // OSVR_UVBI_DUMP_BLOB_CSV
433 
434 #ifdef OSVR_UVBI_FRAMEDROP_HEURISTIC_WARNING
435  if (usableLeds().empty() && prevUsableLedCount > 3 &&
436  assignment.numCompletedMatches() > prevUsableLedCount / 2) {
437  // if we don't have any usable LEDs, last time we had more than 3
438  // (possibly not turning away), and this time we've got blobs that
439  // match at least half of the blobs from last time.
440  msg() << "WARNING: Likely dropped camera frame (reduce CPU load!): "
441  "no usable (identified) LEDs this frame out of "
442  << numMeasurements
443  << " detected likely beacons, while last frame contained "
444  << prevUsableLedCount << " usable LEDs." << std::endl;
445  }
446 #endif
447 
448  return assignment.numCompletedMatches();
449  }
450 
451  void TrackedBodyTarget::disableKalman() { m_impl->permitKalman = false; }
452 
453  void TrackedBodyTarget::permitKalman() { m_impl->permitKalman = true; }
454 
456  CameraParameters const &camParams,
457  osvr::util::time::TimeValue const &tv, BodyState &bodyState,
458  osvr::util::time::TimeValue const &startingTime,
459  bool validStateAndTime) {
460 
463  bodyState.position() -= getStateCorrection();
464 
466  bool permitKalman = m_impl->permitKalman && validStateAndTime;
467 
470 
471  if (!m_hasPoseEstimate && isStateSCAAT(m_impl->trackingState)) {
473  enterRANSACMode();
474  }
475 
477  switch (m_impl->healthEval(bodyState, usableLeds(),
478  m_impl->trackingState)) {
479  case TargetHealthState::StopTrackingErrorBoundsExceeded: {
480  msg() << "In flight reset - error bounds exceeded...";
481 #ifdef OSVR_VERBOSE_ERROR_BOUNDS
482  auto maxPositionalError =
483  getMaxPositionalErrorVariance(getBody().getState());
484  auto distance = getBody().getState().position().z();
485  auto errorLimit = getLimitOnMaxPositionalErrorVariance(distance);
486  std::cout << " [" << maxPositionalError << "\t > " << errorLimit
487  << "\t (@ " << distance << "m)]";
488 #endif
489  std::cout << std::endl;
490 
491  if (m_impl->softResets) {
493  enterRANSACKalmanMode();
494  } else {
495  enterRANSACMode();
496  }
497  break;
498  }
499  case TargetHealthState::StopTrackingLostSight:
500 #if 0
501  msg() << "Lost sight of beacons for too long, awaiting their "
502  "return..."
503  << std::endl;
504 #endif
505  enterRANSACMode();
506  break;
507  case TargetHealthState::HardResetNonFiniteState:
508  msg() << "Hard reset - non-finite target state." << std::endl;
509  enterRANSACMode();
510  break;
511  case TargetHealthState::OK:
512  // we're ok, no transition needed.
513  break;
514  }
516  switch (m_impl->trackingState) {
517  case TargetTrackingState::RANSACWhenBlobDetected: {
518  if (!usableLeds().empty()) {
519  msg()
520  << "In flight reset - beacons detected, re-acquiring fix..."
521  << std::endl;
522  enterRANSACMode();
523  }
524  break;
525  }
526 
527  case TargetTrackingState::RANSACKalmanWhenBlobDetected: {
528  if (!usableLeds().empty()) {
529  msg()
530  << "In flight reset - beacons detected, re-acquiring fix..."
531  << std::endl;
532  enterRANSACKalmanMode();
533  }
534  break;
535  }
536  default:
537  // other states don't have pre-estimation transitions.
538  break;
539  }
540 
542  auto params = EstimatorInOutParams{
543  camParams, m_beacons, m_beaconMeasurementVariance, m_beaconFixed,
544  m_beaconEmissionDirection, startingTime, bodyState,
545  getBody().getProcessModel(), m_beaconDebugData,
546  /*m_targetToBody*/
547  Eigen::Vector3d::Zero()};
548  switch (m_impl->trackingState) {
549  case TargetTrackingState::RANSAC: {
550  m_hasPoseEstimate = m_impl->ransacEstimator(params, usableLeds());
551  m_impl->lastFrameAlgorithm = TargetTrackingState::RANSAC;
552  break;
553  }
554 
555  case TargetTrackingState::RANSACKalman: {
556  m_hasPoseEstimate =
557  m_impl->ransacKalmanEstimator(params, usableLeds(), tv);
558  m_impl->lastFrameAlgorithm = TargetTrackingState::RANSACKalman;
559  break;
560  }
561 
562  case TargetTrackingState::RANSACWhenBlobDetected:
563  case TargetTrackingState::EnteringKalman:
564  case TargetTrackingState::Kalman: {
565  auto videoDt =
566  osvrTimeValueDurationSeconds(&tv, &m_impl->lastEstimate);
567  m_hasPoseEstimate =
568  m_impl->kalmanEstimator(params, usableLeds(), tv, videoDt);
569  m_impl->lastFrameAlgorithm = TargetTrackingState::Kalman;
570  break;
571  }
572  }
573 
575 
576 #ifdef OSVR_DEBUG_ERROR_VARIANCE
577 
578  static ::util::Stride varianceStride(101);
579  if (++varianceStride) {
580  msg() << "Max positional error variance: "
581  << getMaxPositionalErrorVariance(getBody().getState())
582  << " Distance: " << getBody().getState().position().z()
583  << std::endl;
584  }
585 #endif
586 
588  switch (m_impl->trackingState) {
589  case TargetTrackingState::RANSACKalman:
590  case TargetTrackingState::RANSAC: {
591  if (m_hasPoseEstimate && permitKalman) {
592  enterKalmanMode();
593  }
594  break;
595  }
596  case TargetTrackingState::EnteringKalman:
597  m_impl->trackingState = TargetTrackingState::Kalman;
598  // Get one frame pass on the Kalman health check.
599  break;
600  case TargetTrackingState::Kalman: {
601 #ifndef OSVR_RANSACKALMAN
602  auto health = m_impl->kalmanEstimator.getTrackingHealth();
603  switch (health) {
604  case SCAATKalmanPoseEstimator::TrackingHealth::NeedsHardResetNow:
605  msg() << "In flight reset - lost fix..." << std::endl;
606  enterRANSACMode();
607  break;
608  case SCAATKalmanPoseEstimator::TrackingHealth::
609  SoftResetWhenBeaconsSeen:
610 #ifdef OSVR_DEBUG_ERROR_VARIANCE_WHEN_TRACKING_LOST
611  msg() << "Max positional error variance: "
612  << getMaxPositionalErrorVariance(getBody().getState())
613  << std::endl;
614 #endif
615  if (m_impl->softResets) {
616  m_impl->trackingState =
617  TargetTrackingState::RANSACKalmanWhenBlobDetected;
618  } else {
619  m_impl->trackingState =
620  TargetTrackingState::RANSACWhenBlobDetected;
621  }
622  break;
623  case SCAATKalmanPoseEstimator::TrackingHealth::Functioning:
624  // OK!
625  break;
626  }
627 #endif
628  break;
629  }
630  default:
631  // other states don't have post-estimation transitions.
632  break;
633  }
634 
636  m_impl->lastEstimate = tv;
637 
639  bodyState.position() += getStateCorrection();
640 
641  return m_hasPoseEstimate;
642  }
643 
645  CameraParameters const &camParams, Eigen::Vector3d &xlate,
646  Eigen::Quaterniond &quat, int skipBrightsCutoff,
647  std::size_t iterations) {
648 
649  Eigen::Vector3d outXlate;
650  Eigen::Quaterniond outQuat;
651  auto gotPose = m_impl->ransacEstimator(
652  camParams, usableLeds(), m_beacons, m_beaconDebugData, outXlate,
653  outQuat, skipBrightsCutoff, iterations);
654  if (gotPose) {
655  // Post-correct the state
656  xlate = outXlate + computeTranslationCorrectionToBody(outQuat);
657  // copy the quat
658  quat = outQuat;
659  }
660  return gotPose;
661  }
662 
663  Eigen::Vector3d TrackedBodyTarget::getStateCorrection() const {
664 // return m_impl->bodyInterface.state.getQuaternion().conjugate() *
665 // m_beaconOffset;
666 #if 0
667  return computeTranslationCorrection(
668  m_beaconOffset, m_impl->bodyInterface.state.getQuaternion());
669 #endif
670  return computeTranslationCorrectionToBody(
671  m_impl->bodyInterface.state.getQuaternion());
672  }
673 
674  Eigen::Vector3d TrackedBodyTarget::computeTranslationCorrection(
675  Eigen::Vector3d const &bodyFrameOffset,
676  Eigen::Quaterniond const &orientation) {
677  Eigen::Vector3d ret = (Eigen::Isometry3d(orientation) *
678  Eigen::Translation3d(bodyFrameOffset))
679  .translation();
680  return ret;
681  }
682 
683  Eigen::Vector3d TrackedBodyTarget::computeTranslationCorrectionToBody(
684  Eigen::Quaterniond const &orientation) const {
685  return computeTranslationCorrection(m_beaconOffset + m_targetToBody,
686  orientation);
687  }
688 
689  ConfigParams const &TrackedBodyTarget::getParams() const {
690  return m_body.getParams();
691  }
692  std::ostream &TrackedBodyTarget::msg() const {
693  if (getParams().silent) {
694  m_impl->outputSink.str("");
695  return m_impl->outputSink;
696  }
697  return std::cout << "[Tracker Target " << getQualifiedId() << "] ";
698  }
699  void TrackedBodyTarget::enterKalmanMode() {
700  msg() << "Entering SCAAT Kalman mode..." << std::endl;
701  m_impl->trackingState = TargetTrackingState::EnteringKalman;
702  m_impl->kalmanEstimator.resetCounters();
703  }
704 
705  void TrackedBodyTarget::enterRANSACMode() {
706 
707 #ifndef OSVR_UVBI_ASSUME_SINGLE_TARGET_PER_BODY
708 #error \
709  "We may not be able/willing to run right over the body velocity just because this target lost its fix"
710 #endif
711 #ifdef OSVR_DEBUG_ERROR_VARIANCE_WHEN_TRACKING_LOST
712  msg() << "Max positional error variance: "
713  << getMaxPositionalErrorVariance(getBody().getState())
714  << std::endl;
715 #endif
716  m_impl->trackingResets++;
717  // Zero out velocities if we're coming from Kalman.
718  switch (m_impl->trackingState) {
719  case TargetTrackingState::RANSACWhenBlobDetected:
720  case TargetTrackingState::Kalman:
721  getBody().getState().angularVelocity() = Eigen::Vector3d::Zero();
722  getBody().getState().velocity() = Eigen::Vector3d::Zero();
723  break;
724  case TargetTrackingState::EnteringKalman:
726  break;
727  default:
728  break;
729  }
730  m_impl->trackingState = TargetTrackingState::RANSAC;
731  }
732 
733  void TrackedBodyTarget::enterRANSACKalmanMode() {
735  m_impl->trackingResets++;
736 #if 0
737  // Zero out velocities if we're coming from Kalman.
738  switch (m_impl->trackingState) {
739  case TargetTrackingState::RANSACWhenBlobDetected:
740  case TargetTrackingState::Kalman:
741  getBody().getState().angularVelocity() = Eigen::Vector3d::Zero();
742  getBody().getState().velocity() = Eigen::Vector3d::Zero();
743  break;
744  case TargetTrackingState::EnteringKalman:
746  break;
747  default:
748  break;
749  }
750 #endif
751  msg() << "Soft reset as configured..." << std::endl;
752  m_impl->trackingState = TargetTrackingState::RANSACKalman;
753  }
754 
755  LedGroup const &TrackedBodyTarget::leds() const { return m_impl->leds; }
756 
757  LedPtrList const &TrackedBodyTarget::usableLeds() const {
758  return m_impl->usableLeds;
759  }
760 
762  return m_impl->trackingResets;
763  }
764 
765  inline std::ptrdiff_t getNumUsedLeds(LedPtrList const &usableLeds) {
766  return std::count_if(
767  usableLeds.begin(), usableLeds.end(),
768  [](Led const *ledPtr) { return ledPtr->wasUsedLastFrame(); });
769  }
770 
772  TargetStatusMeasurement measurement) const {
773  switch (measurement) {
774  case TargetStatusMeasurement::MaxPosErrorVariance:
775  return getMaxPositionalErrorVariance(getBody().getState());
776  case TargetStatusMeasurement::PosErrorVarianceLimit: {
777  auto distance = getBody().getState().position().z();
778  return getLimitOnMaxPositionalErrorVariance(distance);
779  }
780  case TargetStatusMeasurement::NumUsableLeds:
781  return static_cast<double>(usableLeds().size());
782  case TargetStatusMeasurement::NumUsedLeds:
783  return static_cast<double>(getNumUsedLeds(usableLeds()));
784 
785  default:
786  break;
787  }
788  return 0.0;
789  }
790 
791  LedGroup &TrackedBodyTarget::leds() { return m_impl->leds; }
792 
793  LedPtrList &TrackedBodyTarget::usableLeds() { return m_impl->usableLeds; }
794  void TrackedBodyTarget::updateUsableLeds() {
795  auto &usable = usableLeds();
796  usable.clear();
797  auto &leds = m_impl->leds;
798  for (auto &led : leds) {
799  if (!led.identified()) {
800  continue;
801  }
802  usable.push_back(&led);
803  }
804  }
806  TrackedBodyTarget::getLastUpdate() const {
807  return m_impl->lastEstimate;
808  }
809 
810  void TrackedBodyTarget::dumpBeaconsToConsole() const {
811 
813  auto numBeacons = getNumBeacons();
814  std::cout << "BeaconsID,x,y,z" << std::endl;
815  Eigen::IOFormat ourFormat(Eigen::StreamPrecision, 0, ",");
816  for (UnderlyingBeaconIdType i = 0; i < numBeacons; ++i) {
817  auto id = ZeroBasedBeaconId(i);
818  std::cout << i + 1 << ","
819  << getBeaconAutocalibPosition(id).transpose().format(
820  ourFormat)
821  << "\n";
822  }
823  }
824 
825 } // namespace vbtracker
826 } // namespace osvr
Helper class to keep track of the state of a blob over time. This is used to help determine the ident...
Definition: LED.h:47
OSVR_EXTERN_C_END double osvrTimeValueDurationSeconds(const OSVR_TimeValue *tvA, const OSVR_TimeValue *tvB)
Compute the difference between the two time values, returning the duration as a double-precision floa...
Definition: TimeValueC.h:185
TargetId getId() const
Get the target id within this body.
bool uncalibratedRANSACPoseEstimateFromLeds(CameraParameters const &camParams, Eigen::Vector3d &xlate, Eigen::Quaterniond &quat, int skipBrightsCutoff=-1, std::size_t iterations=5)
StateVector const & stateVector() const
xhat
Definition: PoseState.h:177
A way for targets to access internals of a tracked body.
Eigen::Vector3d getBeaconAutocalibPosition(ZeroBasedBeaconId i) const
std::size_t processLedMeasurements(LedMeasurementVec const &undistortedLeds)
bool permitKalman
Permit as a purely policy measure.
bool updatePoseEstimateFromLeds(CameraParameters const &camParams, osvr::util::time::TimeValue const &tv, BodyState &bodyState, osvr::util::time::TimeValue const &startingTime, bool validStateAndTime)
ConfigParams const & getParams() const
Definition: TrackedBody.cpp:96
Header file for class that tracks and identifies LEDs.
detail::CellGroup< T > cellGroup(const char *groupHeader, T const &data)
Helper function to create a cell group with a group header prefix.
Definition: CSVCellGroup.h:160
void populateStructures()
Must call first, and only once.
bool resumbitMeasurement(LedMeasurement const &meas)
LedPtrList const & usableLeds() const
Get a list of pointers to all recognized, in-range beacons/leds.
double heapSizeFraction() const
The fraction of the theoretical max that the size is.
LedGroup const & leds() const
Get all beacons/leds, including unrecognized ones.
General configuration parameters.
Definition: ConfigParams.h:82
double getInternalStatusMeasurement(TargetStatusMeasurement measurement) const
Header.
size_type size() const
Entries in the heap of possibilities.
TrackedBodyTarget(TrackedBody &body, BodyTargetInterface const &bodyIface, Eigen::Vector3d const &targetToBody, TargetSetupData const &setupData, TargetId id)
bool debug
Whether to show the debug windows and debug messages.
Definition: ConfigParams.h:137
Header.
BodyTargetId getQualifiedId() const
Get a fully-qualified (within a tracking system) id for this target.
LedAndMeasurement getMatch(bool verbose=false)
Requires that hasMoreMatches() has been run and returns true.
Standardized, portable parallel to struct timeval for representing both absolute times and time inter...
Definition: TimeValueC.h:81
Eigen::Vector3d getStateCorrection() const
Get the beacon offset transformed into world space.
detail::Cell< T > cell(const char *header, T const &data)
Helper free function to make a CSV cell.
Definition: CSV.h:401
void resetBeaconAutocalib()
Reset beacon autocalibration position and variance.
double softResetOrientationVariance
Soft reset data incorporation parameter: Orientation variance.
Definition: ConfigParams.h:282
Eigen::Vector3d getBeaconAutocalibVariance(ZeroBasedBeaconId i) const