OSVR-Core
MakeHDKTrackingSystem.h
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 #ifndef INCLUDED_MakeHDKTrackingSystem_h_GUID_B7C07A08_2BF8_45B2_4545_39979BA637E5
26 #define INCLUDED_MakeHDKTrackingSystem_h_GUID_B7C07A08_2BF8_45B2_4545_39979BA637E5
27 
28 // Internal Includes
29 #include "BeaconSetupData.h"
30 #include "ConfigParams.h"
31 #include "HDKData.h"
32 #include "RangeTransform.h"
33 #include "TrackedBody.h"
34 #include "TrackingSystem.h"
35 
36 #include <LoadCalibration.h>
37 #include <cvToEigen.h>
38 
39 // Library/third-party includes
40 // - none
41 
42 // Standard includes
43 #include <iostream>
44 #include <memory>
45 #include <ratio>
46 #include <stdexcept>
47 
48 #undef OSVR_UVBI_DISABLE_AUTOCALIB
49 #undef OSVR_UVBI_DEBUG_EMISSION_DIRECTION
50 #undef DEBUG_REAR_BEACON_TRANSFORM
51 
52 namespace osvr {
53 namespace vbtracker {
54  namespace {
59  static const std::vector<std::string>
60  OsvrHdkLedIdentifier_SENSOR0_PATTERNS = {
61  ".**....*........", // 5
62  "....**...*......", // 6
63  ".*...**.........", // 3
64  ".........*....**", // 4
65  "..*.....**......", // 1
66  "*......**.......", // 2
67  "....*.*..*......", // 10
68  ".*.*.*..........", // 8
69  ".........*.**...", // 9
70  "**...........*..", // 7
71  "....*.*......*..", // 11
72  "*.......*.*.....", // 28
73  ".*........*.*...", // 27
74  ".*.........*.*..", // 25
75  "..*..*.*........", // 15
76  "....*...*.*.....", // 16
77  "...*.*........*.", // 17
78  "...*.....*.*....", // 18
79  "....*......*..*.", // 19
80  "....*..*....*...", // 20
81  "..*...*........*", // 21
82  "........*..*..*.", // 22
83  ".......*...*...*", // 23
84  "......*...*..*..", // 24
85  ".......*....*..*", // 14
86  "..*.....*..*....", // 26
87  "*....*....*.....", // 13
88  "...*....*...*...", // 12
89  "..*.....*...*...", // 29
90  "...*......*...*.", // 30
91  "***...*........*", // 31
92  "...****..*......", // 32
93  "*.*..........***", // 33
94  "**...........***" // 34
95  };
96 
99  static const std::vector<std::string>
100  OsvrHdkLedIdentifier_SENSOR1_PATTERNS = {
101  "X............**..", // 37 31 // unused in production
102  "......**.*......", // 38 32
103  ".............***", // 39 33
104  "X..........*.....", // 40 34 // unused in production
105  "...*.......**...", // 33 27
106  "...**.....*....." // 34 28
107  };
108  static const auto SCALE_FACTOR = std::milli::den; // mm to m
109 
110  template <typename Scalar> using cvMatx33 = cv::Matx<Scalar, 3, 3>;
111 
113  template <typename Scalar> inline cvMatx33<Scalar> get180AboutY() {
114  auto ret = cvMatx33<Scalar>::eye();
115  // flip sign of x and z axes to get equivalent to exact 180 degree
116  // rotation about y.
117  ret(0, 0) = -1;
118  ret(2, 2) = -1;
119  return ret;
120  }
121 
123  template <typename Scalar> inline cvMatx33<Scalar> getTransform() {
124  // flip sign of x and z axes to make the HDK coordinate system match
125  // our desired one: this is equivalent to 180 degree rotation about
126  // y.
127  return get180AboutY<Scalar>();
128  }
129 
131  template <typename Scalar>
132  inline cvMatx33<Scalar> getTransformAndScale() {
133  return getTransform<Scalar>() * (Scalar(1) / Scalar(SCALE_FACTOR));
134  }
135 
137  template <typename Scalar>
138  inline cv::Point3_<Scalar>
139  transformFromHDKData(cv::Point3_<Scalar> input) {
140  static const cvMatx33<Scalar> xformMatrix =
141  getTransformAndScale<Scalar>();
142  return xformMatrix * input;
143  }
144 
146  template <typename Scalar>
147  inline cv::Vec<Scalar, 3>
148  transformFromHDKData(cv::Vec<Scalar, 3> input) {
149  static const cvMatx33<Scalar> xformMatrix = getTransform<Scalar>();
150  return xformMatrix * input;
151  }
152 
153  inline LocationPoint rotatePoint180AboutY(LocationPoint pt) {
154  pt.x *= -1;
155  pt.z *= -1;
156  return pt;
157  }
158  } // namespace
159 
161  inline bool tryLoadingCalibration(std::string const &filename,
162  TargetSetupData &data) {
163 
167  auto calibratedLocations = tryLoadingArrayOfPointsFromFile(filename);
168 
169  auto n = calibratedLocations.size();
170  const auto numFrontBeacons = getNumHDKFrontPanelBeacons();
171  const auto numRearBeacons = getNumHDKRearPanelBeacons();
174  if (n == numFrontBeacons || n == (numFrontBeacons + numRearBeacons)) {
175 
178  calibratedLocations.resize(numFrontBeacons);
180  calibratedLocations, begin(data.locations),
181  [](LocationPoint pt) { return transformFromHDKData(pt); });
184  for (std::size_t i = 0; i < numFrontBeacons; ++i) {
185  data.initialAutocalibrationErrors[i] *=
186  BEACON_AUTOCALIB_ERROR_SCALE_IF_CALIBRATED;
187  }
188  return true;
189  }
190  return false;
191  }
192 
193  inline Point3Vector const &getTarget0Locations(BuiltInTargetSets target) {
194  switch (target) {
195  case BuiltInTargetSets::HDK1xChassis:
196  return OsvrHdkLedLocations_SENSOR0;
197  break;
198  case BuiltInTargetSets::HDK2Chassis:
200  break;
201  }
202  }
203 
204  inline Point3Vector const &getTarget1Locations(BuiltInTargetSets target) {
205  switch (target) {
206  case BuiltInTargetSets::HDK1xChassis:
207  return OsvrHdkLedLocations_SENSOR1;
208  break;
209  case BuiltInTargetSets::HDK2Chassis:
210  return OsvrHdk2LedLocations_SENSOR1;
211  break;
212  }
213  }
214 
215  inline std::unique_ptr<TrackingSystem>
217  auto silent = params.silent;
218 
219  std::unique_ptr<TrackingSystem> sys(new TrackingSystem(params));
220 #ifdef OSVR_UVBI_DEBUG_EMISSION_DIRECTION
221  {
222  auto xform = getTransform<float>();
223  std::cout << "Transform matrix:\n" << xform << std::endl;
224  }
226  auto sampleBeacons = {5, 32, 9, 10};
227 #endif
228 
229  auto hmd = sys->createTrackedBody();
230  if (!hmd) {
231  throw std::runtime_error(
232  "Could not create a tracked body for the HMD!");
233  }
234 
235  const auto numFrontBeacons = getNumHDKFrontPanelBeacons();
236  const auto numRearBeacons = getNumHDKRearPanelBeacons();
237  const auto useRear = params.includeRearPanel;
238  const auto numBeacons =
239  numFrontBeacons + (useRear ? numRearBeacons : 0);
240 
242  TargetSetupData data;
243  data.setBeaconCount(numBeacons, BaseMeasurementVariance,
244  params.initialBeaconError);
245 
247  data.patterns = OsvrHdkLedIdentifier_SENSOR0_PATTERNS;
248 
249  if (useRear) {
251  data.patterns.insert(end(data.patterns),
252  begin(OsvrHdkLedIdentifier_SENSOR1_PATTERNS),
253  end(OsvrHdkLedIdentifier_SENSOR1_PATTERNS));
254  }
255 
258  auto locationsEnd = range_transform(
259  getTarget0Locations(params.targetSet), begin(data.locations),
260  [](LocationPoint pt) { return transformFromHDKData(pt); });
261 
263  if (!params.calibrationFile.empty()) {
264  auto success = tryLoadingCalibration(params.calibrationFile, data);
265  if (!silent) {
266  if (success) {
267  messages::loadedCalibFileSuccessfully(
268  params.calibrationFile);
269  }
270  }
271  }
272 
273  if (useRear) {
274  // distance between front and back panel target origins, in mm,
275  // because we'll apply this before converting coordinate
276  // systems.
277  // Yes, all these transformations have been checked.
278  const auto distanceBetweenPanels = computeDistanceBetweenPanels(
279  params.headCircumference,
281 
283  auto transformBackPoints =
284  [distanceBetweenPanels](LocationPoint pt) {
285  auto p = rotatePoint180AboutY(pt) -
286  LocationPoint(0, 0, distanceBetweenPanels);
287  return transformFromHDKData(p);
288  };
289  range_transform(getTarget1Locations(params.targetSet), locationsEnd,
290  transformBackPoints);
291 #ifdef DEBUG_REAR_BEACON_TRANSFORM
292  std::cout << "Front beacon position (id 32): "
293  << data.locations[32 - 1] << " (originally "
294  << OsvrHdkLedLocations_SENSOR0[32 - 1] << ")"
295  << std::endl;
296  std::cout << "Back beacon position (id 40): "
297  << data.locations[40 - 1] << " (originally "
298  << OsvrHdkLedLocations_SENSOR1.back() << ")" << std::endl;
299 #endif
300  }
301 
304  OsvrHdkLedDirections_SENSOR0, begin(data.emissionDirections),
305  [](EmissionDirectionVec v) { return transformFromHDKData(v); });
306 
307  if (useRear) {
308  // Resize down - so we can resize up to fill
309  // those last elements with constant values.
310  data.emissionDirections.resize(numFrontBeacons);
311  data.emissionDirections.resize(
312  numBeacons,
313  transformFromHDKData(EmissionDirectionVec(0, 0, -1)));
314  }
315 #ifdef OSVR_UVBI_DEBUG_EMISSION_DIRECTION
316  for (auto &beaconOneBased : sampleBeacons) {
317  std::cout << "Beacon ID " << beaconOneBased
318  << " emission direction "
319  << data.emissionDirections[beaconOneBased - 1]
320  << std::endl;
321  }
322 #endif
323 
324 #ifdef OSVR_UVBI_DISABLE_AUTOCALIB
325  for (decltype(numBeacons) i = 0; i < numBeacons; ++i) {
327  data.markBeaconFixed(makeOneBased(ZeroBasedBeaconId(i)));
328  }
329 #else
330  for (auto idx : {16, 17, 19, 20}) {
333  data.markBeaconFixed(OneBasedBeaconId(idx));
334  }
335 #endif
336 
338 #if 0
339  std::copy(begin(OsvrHdkLedVariances_SENSOR0),
341  begin(data.baseMeasurementVariances));
342 #endif
343 
345  if (params.targetSet == BuiltInTargetSets::HDK2Chassis) {
346  for (auto id : getOneBasedIDsOfMissingBeaconsHDK2()) {
347  data.markBeaconInactive(OneBasedBeaconId(id));
348  }
349  }
350 
352  auto summary = data.cleanAndValidate(params.silent);
353 
354  auto opticalTarget = hmd->createTarget(
355 #if 0
356  Eigen::Vector3d(0, 0, 0.04141),
357 #else
358  Eigen::Vector3d::Zero(),
359 #endif
360  data);
361 
362  if (!opticalTarget) {
363  throw std::runtime_error(
364  "Could not create a tracked target for the HMD!");
365  }
366 
367  auto wantIMU =
368  !params.imu.path.empty() &&
369  (params.imu.useAngularVelocity || params.imu.useOrientation ||
370  params.imu.calibrateAnyway);
371  if (wantIMU) {
372  auto imu =
373  hmd->createIntegratedIMU(params.imu.orientationVariance,
375  if (!imu) {
376  throw std::runtime_error("Could not create an integrated "
377  "IMU object for the HMD!");
378  }
379  } else {
382  sys->setCameraPose(Eigen::Isometry3d(Eigen::Translation3d(
383  Eigen::Vector3d::Map(params.cameraPosition))));
384  }
385  return sys;
386  }
387 } // namespace vbtracker
388 } // namespace osvr
389 
390 #endif // INCLUDED_MakeHDKTrackingSystem_h_GUID_B7C07A08_2BF8_45B2_4545_39979BA637E5
OutIter range_transform(Container &&c, OutIter dest, Func &&f)
Wrapper for std::transform that does the begin and end business for us.
Definition: RangeTransform.h:44
double angularVelocityVariance
units: (rad/sec)^2
Definition: ConfigParams.h:63
bool silent
For optimization usage.
Definition: ConfigParams.h:89
const std::vector< double > OsvrHdkLedVariances_SENSOR0
generated by python script in this directory.
Definition: HDKData.cpp:182
bool includeRearPanel
If true, this will replace the two sensors with just a single one, including the beacons at the back ...
Definition: ConfigParams.h:183
std::string calibrationFile
If non-empty, the file to load (or save to) for calibration data.
Definition: ConfigParams.h:251
The main namespace for all C++ elements of the framework, internal and external.
Definition: namespace_osvr.dox:3
std::unique_ptr< TrackingSystem > makeHDKTrackingSystem(ConfigParams const &params)
Definition: MakeHDKTrackingSystem.h:216
double initialBeaconError
Initial beacon error for autocalibration (units: m^2).
Definition: ConfigParams.h:130
Definition: ForwardDeclarations.h:236
Definition: TrackingSystem.h:54
Header.
bool tryLoadingCalibration(std::string const &filename, TargetSetupData &data)
returns true if it actually did load one.
Definition: MakeHDKTrackingSystem.h:161
const Point3Vector OsvrHdk2LedLocations_SENSOR0
Locations on the HDK2 chassis - for LEDs that the HDK2 lacks, the HDK1 values were used as placeholde...
Definition: HDKData.cpp:95
double orientationVariance
units: rad^2
Definition: ConfigParams.h:55
IMUInputParams imu
IMU input-related parameters.
Definition: ConfigParams.h:254
bool calibrateAnyway
Should we use the IMU orientation data for calibration even if useOrientation is false?
Definition: ConfigParams.h:49
BuiltInTargetSets targetSet
When using hard-coded target sets, which one to use.
Definition: ConfigParams.h:108
General configuration parameters.
Definition: ConfigParams.h:82
Header.
Data for a full target (all the beacons), unswizzled into a "struct of vectors".
Definition: BeaconSetupData.h:53
OneBasedBeaconId makeOneBased(ZeroBasedBeaconId id)
Overloaded conversion function to turn any beacon ID into one-based, respecting the convention that n...
Definition: BeaconIdTypes.h:79
double cameraPosition[3]
x, y, z, with y up, all in meters.
Definition: ConfigParams.h:257
bool useAngularVelocity
Should angular velocity reports be used once calibration completes?
Definition: ConfigParams.h:60
float computeDistanceBetweenPanels(ConfigParams const &config)
distance between front and back panel target origins, in mm.
Definition: SetupSensors.h:68
double headCircumference
Head circumference at the head strap, in cm - 55.75 is our estimate for an average based on some hat ...
Definition: ConfigParams.h:188
Definition: Transform.h:43
bool useOrientation
Should orientation reports be used once calibration completes?
Definition: ConfigParams.h:52
double Scalar
Common scalar type.
Definition: FlexibleKalmanBase.h:48
double headToFrontBeaconOriginDistance
This is the distance fron the front of the head to the origin of the front sensor coordinate system i...
Definition: ConfigParams.h:194
BuiltInTargetSets
If you add an entry here, must also update both getConfigStringForTargetSet and AllBuiltInTargetSets ...
Definition: ConfigParams.h:79