NASA Astrobee Robot Software  Astrobee Version:
Flight software for the Astrobee robots operating inside the International Space Station.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
vive.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 LOCALIZATION_VIVE_LOCALIZATION_SRC_VIVE_H_
20 #define LOCALIZATION_VIVE_LOCALIZATION_SRC_VIVE_H_
21 
22 // FSW code
25 #include <ff_common/ff_names.h>
26 
27 // Messages
28 #include <geometry_msgs/TransformStamped.h>
29 #include <ff_hw_msgs/ViveLighthouses.h>
30 #include <ff_hw_msgs/ViveTrackers.h>
31 #include <ff_hw_msgs/ViveLight.h>
32 #include <ff_msgs/CameraRegistration.h>
33 #include <ff_msgs/VisualLandmarks.h>
34 
35 // We will use OpenCV to bootstrap solution
36 #include <opencv2/calib3d/calib3d.hpp>
37 
38 // Eigen
39 #include <Eigen/Core>
40 #include <Eigen/Geometry>
41 
42 // STL
43 #include <string>
44 #include <vector>
45 #include <map>
46 
50 namespace vive_localization {
51 
52 // Universal constants
53 static constexpr size_t NUM_SENSORS = 32;
54 
55 // ESSENTIAL STRUCTURES
56 
57 // Lighthouse parameters
58 enum Params {
65 };
66 
67 // Lighthouse parameters
68 enum Errors {
74 };
75 
76 enum Motors {
80 };
81 
82 // Lighthouse data structure
83 struct Lighthouse {
84  std::string serial;
85  double vTl[6];
87  bool ready;
88 };
89 typedef std::map<uint8_t, Lighthouse> LighthouseMap;
90 
91 // Tracker data structure
92 struct Tracker {
93  double bTh[6];
94  double tTh[6];
95  double tTi[6];
96  double sensors[NUM_SENSORS*6];
97  double errors[NUM_ERRORS][3];
98  bool ready;
99 };
100 typedef std::map<std::string, Tracker> TrackerMap;
101 
102 // Pulse measurements
103 struct Measurement {
104  double wTb[6];
105  ff_hw_msgs::ViveLight light;
106 };
107 typedef std::map<ros::Time, Measurement> MeasurementMap;
108 
109 // Correction data structure
110 typedef std::map<ros::Time, geometry_msgs::TransformStamped> CorrectionMap;
111 
112 // TRANSFORM ENGINE
113 
114 void SendStaticTransform(geometry_msgs::TransformStamped const& tfs);
115 
116 void SendDynamicTransform(geometry_msgs::TransformStamped const& tfs);
117 
118 void SendTransforms(
119  std::string const& frame_world, // World name
120  std::string const& frame_vive, // Vive frame name
121  std::string const& frame_body, // Body frame name
122  double registration[6],
123  LighthouseMap const& lighthouses, TrackerMap const& trackers);
124 
125 // Convert a ceres to an Eigen transform
126 Eigen::Affine3d CeresToEigen(double ceres[6], bool invert = false);
127 
128 // Convert a Euler angle to a Quaternion
129 Eigen::Quaterniond toQuaternion(double roll, double pitch, double yaw);
130 
131 // CONFIG RELATED CALLS
132 
133 // Read Vive trajectory modification parameter
135  Eigen::Vector3d & modification_vector,
136  Eigen::Quaterniond & modification_quaternion);
137 
138 // Read lighthouse data
140  std::map<std::string, Eigen::Affine3d> & lighthouses);
141 
142 // Read tracker data
144  std::map<std::string, Tracker> & trackers);
145 
146 // Read registration data
147 bool ReadRegistrationConfig(config_reader::ConfigReader *config, double T[6]);
148 
149 // REUSABLE CALLS
150 
151 void LighthouseCallback(ff_hw_msgs::ViveLighthouses::ConstPtr const& msg,
152  LighthouseMap & lighthouses);
153 
154 void TrackerCallback(ff_hw_msgs::ViveTrackers::ConstPtr const& msg,
155  TrackerMap & trackers);
156 
157 // Estimate a pose from (image) <-> (world) correspondences
158 bool SolvePnP(std::vector<cv::Point3f> const& obj,
159  std::vector<cv::Point2f> const& img,
160  Eigen::Affine3d & transform);
161 
162 // TRACKING ROUTINES
163 
164 // This algorithm solves the Procrustes problem in that it finds an affine transform
165 // (rotation, translation, scale) that maps the "in" matrix to the "out" matrix
166 // Code from: https://github.com/oleg-alexandrov/projects/blob/master/eigen/Kabsch.cpp
167 // License is that this code is release in the public domain... Thanks, Oleg :)
168 template <typename T>
169 static bool Kabsch(
170  Eigen::Matrix<T, 3, Eigen::Dynamic> in,
171  Eigen::Matrix<T, 3, Eigen::Dynamic> out,
172  Eigen::Transform<T, 3, Eigen::Affine> &A, bool allowScale) {
173  // Default output
174  A.linear() = Eigen::Matrix<T, 3, 3>::Identity(3, 3);
175  A.translation() = Eigen::Matrix<T, 3, 1>::Zero();
176  // A simple check to see that we have a sufficient number of correspondences
177  if (in.cols() < 4) {
178  // ROS_WARN("Visualeyez needs to see at least four LEDs to track");
179  return false;
180  }
181  // A simple check to see that we have a sufficient number of correspondences
182  if (in.cols() != out.cols()) {
183  // ROS_ERROR("Same number of points required in input matrices");
184  return false;
185  }
186  // First find the scale, by finding the ratio of sums of some distances,
187  // then bring the datasets to the same scale.
188  T dist_in = T(0.0), dist_out = T(0.0);
189  for (int col = 0; col < in.cols()-1; col++) {
190  dist_in += (in.col(col+1) - in.col(col)).norm();
191  dist_out += (out.col(col+1) - out.col(col)).norm();
192  }
193  if (dist_in <= T(0.0) || dist_out <= T(0.0))
194  return true;
195  T scale = T(1.0);
196  if (allowScale) {
197  scale = dist_out/dist_in;
198  out /= scale;
199  }
200  // Find the centroids then shift to the origin
201  Eigen::Matrix<T, 3, 1> in_ctr = Eigen::Matrix<T, 3, 1>::Zero();
202  Eigen::Matrix<T, 3, 1> out_ctr = Eigen::Matrix<T, 3, 1>::Zero();
203  for (int col = 0; col < in.cols(); col++) {
204  in_ctr += in.col(col);
205  out_ctr += out.col(col);
206  }
207  in_ctr /= T(in.cols());
208  out_ctr /= T(out.cols());
209  for (int col = 0; col < in.cols(); col++) {
210  in.col(col) -= in_ctr;
211  out.col(col) -= out_ctr;
212  }
213  // SVD
214  Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> Cov = in * out.transpose();
215  Eigen::JacobiSVD < Eigen::Matrix < T, Eigen::Dynamic, Eigen::Dynamic > > svd(Cov,
216  Eigen::ComputeThinU | Eigen::ComputeThinV);
217  // Find the rotation
218  T d = (svd.matrixV() * svd.matrixU().transpose()).determinant();
219  if (d > T(0.0))
220  d = T(1.0);
221  else
222  d = T(-1.0);
223  Eigen::Matrix<T, 3, 3> I = Eigen::Matrix<T, 3, 3>::Identity(3, 3);
224  I(2, 2) = d;
225  Eigen::Matrix<T, 3, 3> R = svd.matrixV() * I * svd.matrixU().transpose();
226  // The final transform
227  A.linear() = scale * R;
228  A.translation() = scale*(out_ctr - R*in_ctr);
229  // Success
230  return true;
231 }
232 
233 // Given a point in space, predict the lighthouse angle
234 template <typename T>
235 static void Predict(T const* params, T const* xyz, T* ang, bool correct) {
236  for (size_t i = 0; i < 2; i++) {
237  T a = xyz[2];
238  T b = -xyz[0];
239  T c = xyz[1];
240  if (i == 1) {
241  a = xyz[2];
242  b = -xyz[1];
243  c = -xyz[0];
244  }
245  // Ideal angle in radians [0, 2pi] relative to the start of the sweep
246  ang[i] = atan2(a, b);
247  // Perturb this angle based on the base station parameters
248  if (correct) {
249  T const* p = &params[i*NUM_PARAMS];
250  // Motor correction
251  ang[i] -= p[PARAM_PHASE];
252  ang[i] -= asin((c * tan(p[PARAM_TILT])) / sqrt(a*a + b*b));
253  // Lens correction
254  ang[i] -= p[PARAM_GIB_MAG] * cos(ang[i] + p[PARAM_GIB_PHASE]);
255  ang[i] -= p[PARAM_CURVE] * atan2(c, a) * atan2(c, a);
256  }
257  }
258 }
259 
260 // Given the lighthouse angle, predict the point in space
261 template <typename T>
262 static void Correct(T const* params, T * angle, bool correct) {
263  if (correct) {
264  T ideal[2], pred[2], xyz[3];
265  ideal[0] = angle[0];
266  ideal[1] = angle[1];
267  for (size_t i = 0; i < 10; i++) {
268  xyz[0] = T(-1.0) / tan(ideal[0]);
269  xyz[1] = T(-1.0) / tan(ideal[1]);
270  xyz[2] = T(1.0);
271  Predict(params, xyz, pred, correct);
272  ideal[0] += (angle[0] - pred[0]);
273  ideal[1] += (angle[1] - pred[1]);
274  }
275  angle[0] = ideal[0];
276  angle[1] = ideal[1];
277  }
278 }
279 
280 } // namespace vive_localization
281 
282 #endif // LOCALIZATION_VIVE_LOCALIZATION_SRC_VIVE_H_
vive_localization::NUM_PARAMS
@ NUM_PARAMS
Definition: vive.h:64
vive_localization::Tracker::sensors
double sensors[NUM_SENSORS *6]
Definition: vive.h:96
vive_localization::Tracker
Definition: vive.h:92
vive_localization::Tracker::errors
double errors[NUM_ERRORS][3]
Definition: vive.h:97
vive_localization::Lighthouse::vTl
double vTl[6]
Definition: vive.h:85
vive_localization::SendStaticTransform
void SendStaticTransform(geometry_msgs::TransformStamped const &tfs)
Definition: vive.cc:38
vive_localization::LighthouseCallback
void LighthouseCallback(ff_hw_msgs::ViveLighthouses::ConstPtr const &msg, LighthouseMap &lighthouses)
Definition: vive.cc:263
vive_localization::PARAM_CURVE
@ PARAM_CURVE
Definition: vive.h:63
vive_localization::ERROR_ACC_BIAS
@ ERROR_ACC_BIAS
Definition: vive.h:71
vive_localization::ReadRegistrationConfig
bool ReadRegistrationConfig(config_reader::ConfigReader *config, double T[6])
Definition: vive.cc:239
vive_localization::TrackerMap
std::map< std::string, Tracker > TrackerMap
Definition: vive.h:100
vive_localization::ERROR_GYR_BIAS
@ ERROR_GYR_BIAS
Definition: vive.h:69
vive_localization::Errors
Errors
Definition: vive.h:68
vive_localization::Tracker::ready
bool ready
Definition: vive.h:98
vive_localization::Params
Params
Definition: vive.h:58
vive_localization::Measurement::light
ff_hw_msgs::ViveLight light
Definition: vive.h:105
vive_localization::NUM_SENSORS
static constexpr size_t NUM_SENSORS
Definition: vive.h:53
vive_localization::PARAM_PHASE
@ PARAM_PHASE
Definition: vive.h:59
vive_localization::ReadModificationVector
bool ReadModificationVector(config_reader::ConfigReader *config, Eigen::Vector3d &modification_vector, Eigen::Quaterniond &modification_quaternion)
Definition: vive.cc:162
vive_localization::ERROR_ACC_SCALE
@ ERROR_ACC_SCALE
Definition: vive.h:72
vive_localization::SendDynamicTransform
void SendDynamicTransform(geometry_msgs::TransformStamped const &tfs)
Definition: vive.cc:43
vive_localization::SendTransforms
void SendTransforms(std::string const &frame_world, std::string const &frame_vive, std::string const &frame_body, double registration[6], LighthouseMap const &lighthouses, TrackerMap const &trackers)
Definition: vive.cc:48
point_cloud_common::Vector3d
Eigen::Vector3d Vector3d(const PointType &point)
Definition: utilities.h:328
vive_localization::Correct
static void Correct(T const *params, T *angle, bool correct)
Definition: vive.h:262
vive_localization::Tracker::tTi
double tTi[6]
Definition: vive.h:95
ff_names.h
vive_localization::Lighthouse::params
double params[NUM_MOTORS *NUM_PARAMS]
Definition: vive.h:86
vive_localization::CorrectionMap
std::map< ros::Time, geometry_msgs::TransformStamped > CorrectionMap
Definition: vive.h:110
vive_localization::Lighthouse
Definition: vive.h:83
vive_localization::LighthouseMap
std::map< uint8_t, Lighthouse > LighthouseMap
Definition: vive.h:89
vive_localization::Lighthouse::ready
bool ready
Definition: vive.h:87
vive_localization::CeresToEigen
Eigen::Affine3d CeresToEigen(double ceres[6], bool invert)
Definition: vive.cc:125
config_reader::ConfigReader
Definition: config_reader.h:48
vive_localization::Tracker::bTh
double bTh[6]
Definition: vive.h:93
vive_localization::TrackerCallback
void TrackerCallback(ff_hw_msgs::ViveTrackers::ConstPtr const &msg, TrackerMap &trackers)
Definition: vive.cc:282
vive_localization::MOTOR_HORIZONTAL
@ MOTOR_HORIZONTAL
Definition: vive.h:78
vive_localization
Definition: vive.cc:34
vive_localization::PARAM_GIB_MAG
@ PARAM_GIB_MAG
Definition: vive.h:62
tfs
geometry_msgs::TransformStamped tfs
Definition: teleop_tool.cc:80
vive_localization::MOTOR_VERTICAL
@ MOTOR_VERTICAL
Definition: vive.h:77
config_reader.h
vive_localization::ERROR_GYR_SCALE
@ ERROR_GYR_SCALE
Definition: vive.h:70
vive_localization::Motors
Motors
Definition: vive.h:76
optimization_common::Affine3d
Eigen::Affine3d Affine3d(const Eigen::Matrix< double, 7, 1 > &affine_vector)
Definition: utilities.cc:43
vive_localization::Measurement::wTb
double wTb[6]
Definition: vive.h:104
vive_localization::PARAM_TILT
@ PARAM_TILT
Definition: vive.h:60
vive_localization::PARAM_GIB_PHASE
@ PARAM_GIB_PHASE
Definition: vive.h:61
vive_localization::toQuaternion
Eigen::Quaterniond toQuaternion(double roll, double pitch, double yaw)
Definition: vive.cc:143
msg_conversions.h
vive_localization::NUM_MOTORS
@ NUM_MOTORS
Definition: vive.h:79
vive_localization::ReadLighthouseConfig
bool ReadLighthouseConfig(config_reader::ConfigReader *config, std::map< std::string, Eigen::Affine3d > &lighthouses)
Definition: vive.cc:178
vive_localization::Predict
static void Predict(T const *params, T const *xyz, T *ang, bool correct)
Definition: vive.h:235
vive_localization::Measurement
Definition: vive.h:103
vive_localization::Lighthouse::serial
std::string serial
Definition: vive.h:84
vive_localization::NUM_ERRORS
@ NUM_ERRORS
Definition: vive.h:73
vive_localization::SolvePnP
bool SolvePnP(std::vector< cv::Point3f > const &obj, std::vector< cv::Point2f > const &img, Eigen::Affine3d &transform)
Definition: vive.cc:375
vive_localization::Kabsch
static bool Kabsch(Eigen::Matrix< T, 3, Eigen::Dynamic > in, Eigen::Matrix< T, 3, Eigen::Dynamic > out, Eigen::Transform< T, 3, Eigen::Affine > &A, bool allowScale)
Definition: vive.h:169
vive_localization::MeasurementMap
std::map< ros::Time, Measurement > MeasurementMap
Definition: vive.h:107
vive_localization::ReadTrackerConfig
bool ReadTrackerConfig(config_reader::ConfigReader *config, std::map< std::string, Tracker > &trackers)
Definition: vive.cc:206
vive_localization::Tracker::tTh
double tTh[6]
Definition: vive.h:94