PivotCalibrationVrepPlugin.hpp
Go to the documentation of this file.
1 #ifndef _PIVOT_CALIBRATION_VREP_PLUGIN_HPP_
2 #define _PIVOT_CALIBRATION_VREP_PLUGIN_HPP_
3 
4 #include <iostream>
5 #include <memory>
6 
7 #include <boost/log/trivial.hpp>
8 #include <boost/exception/all.hpp>
9 #include <boost/algorithm/string.hpp>
10 
11 #include "grl/vrep/Eigen.hpp"
12 #include "grl/vrep/Vrep.hpp"
13 #include "TRTK/PivotCalibration.hpp"
14 
15 #include "v_repLib.h"
16 
17 /// @todo move elsewhere, because it will conflict with others' implementations of outputting vectors
18 template<typename T>
19 inline boost::log::formatting_ostream& operator<<(boost::log::formatting_ostream& out, std::vector<T>& v)
20 {
21  out << "[";
22  size_t last = v.size() - 1;
23  for(size_t i = 0; i < v.size(); ++i) {
24  out << v[i];
25  if (i != last)
26  out << ", ";
27  }
28  out << "]";
29  return out;
30 }
31 
32 namespace grl {
33 
34 
35 
36 /// Creates a complete vrep plugin object
37 /// usage:
38 /// @code
39 /// auto pivotCalib = std::make_shared<grl::PivotCalibrationVrepPlugin>();
40 /// pivotCalib->construct();
41 /// // move objects to new position
42 /// @endcode
43 ///
44 /// @todo the rotation component may be different between the
45 class PivotCalibrationVrepPlugin : public std::enable_shared_from_this<PivotCalibrationVrepPlugin> {
46 public:
47 
48  static const bool debug = false;
49 
50  enum ParamIndex {
51  ToolTipToModifyName, ///< V-REP handle string for the tip of the tool that will be *modified*
52  ToolTipToMeasureName, ///< V-REP handle string for the tip of the tool that will be *measured*
53  ToolBaseToModifyName, ///< V-REP handle string for the base of the tool that will be *modified*
54  ToolBaseToMeasureName, ///< V-REP handle string for the base of the tool that will be *measured*
55  };
56 
57  typedef std::tuple<
58  std::string,
59  std::string,
60  std::string,
61  std::string
62  > Params;
63 
64 
65  static const Params defaultParams(){
66  return std::make_tuple(
67  "RobotMillTip" , // ToolTipToModifyHandle,
68  "Fiducial#55" , // ToolTipToMeasureHandle,
69  "RobotFlangeTip" , // ToolTipHandle,
70  "Fiducial#22" // ToolBaseHandle,
71  );
72  }
73 
74 /// @todo allow KukaFRIThreadSeparator parameters to be updated
76  :
77  isFirstFrame(true),
78  frameCount(0),
79  params_(params)
80 {
81 /// @todo figure out how to re-enable when .so isn't loaded
82  // initHandles();
83 
84 }
85 
86 /// construct() function completes initialization of the plugin
87 /// @todo move this into the actual constructor, but need to correctly handle or attach vrep shared libraries for unit tests.
88 void construct(){
89  initHandles();
90 
91  // set the current transformEstimate to the initial estimate already in vrep
92  if(allHandlesSet) transformEstimate = getObjectTransform(toolTip,toolBase);
93 }
94 
95 /// Possible algorithms are:
96 /// TWO_STEP_PROCEDURE, //!< First, estimate the pivot point in global coordinates. Second, estimate the sought translation by computing the difference vector between the pivot point and the center of the sensor system; then take the mean.\n This algorithm is advantageous in the case of zero-mean noise.
97 /// COMBINATORICAL_APPROACH //!< Setup n equations that yield the pivot point from a single measurement using the sought (but unknown) translation. Eliminate the pivot point in the system of equations and finally solve for the sought translation. \n This algorithm is advantageous in the case of non-zero-mean noise (e.g. a systematic error).
98 ///
99 /// If the algorithm string doesn't match an existing algorithm, this API will assume TWO_STEP_PROCEDURE.
100 void setAlgorithm(std::string algorithm_){
101  algorithm = algorithm_;
102  // if (boost::iequals(algorithm, std::string("COMBINATORICAL_APPROACH"))) algorithm = TRTK::PivotCalibration<double>::Algorithm::COMBINATORICAL_APPROACH;
103  // else algorithm = TRTK::PivotCalibration<double>::Algorithm::TWO_STEP_PROCEDURE;
104 }
105 
106 void addFrame() {
107  BOOST_LOG_TRIVIAL(trace) << "Adding pivot calibration frame #" << ++frameCount << std::endl;
108 
109  auto toolTipInToolBase = getObjectTransform(toolTip,toolBase);
110 
111  if(isFirstFrame){
112  firstToolTipInToolBaseInverse = toolTipInToolBase.inverse();
113  isFirstFrame = false;
114  }
115 
116  auto toolTipInFirstTipBase = firstToolTipInToolBaseInverse * toolTipInToolBase; // A_0_Inv * A_i
117 
118 
119  rvecsArm.push_back( toolTipInFirstTipBase.rotation().matrix());
120  tvecsArm.push_back( toolTipInFirstTipBase.translation() );
121 
122 
123  if(debug){
124 
125  std::cout << "\ntoolTipInToolBase:\n" << poseString(toolTipInToolBase) << "\n";
126 
127  std::cout << "\ntoolTipInFirstTipBase:\n" << poseString(toolTipInFirstTipBase) << "\n";
128 
129  // print simulation transfrom from tip to fiducial
130  Eigen::Affine3d ToolTipToFiducial = getObjectTransform(toolTip,toolBase);
131  BOOST_LOG_TRIVIAL(info) << "\n" << poseString(ToolTipToFiducial,"expected ToolBaseToToolTip (simulation only): ") << std::endl;
132  }
133 }
134 
135 /// @brief run solver to estimate the unknown transform and set the simulation to the estimated value
136 ///
137 /// after calling addFrame a number of times in different positions and orientations
138 ///
139 /// @todo evaluate if applyEstimate should not be called by this
141 
142  BOOST_LOG_TRIVIAL(trace) << "Running Pivot Calibration Estimate with the following numbers of entries in each category: rvecsFiducial" << " rvecsArm: " << rvecsArm.size() << " tvecsArm: " << tvecsArm.size() << std::endl;
143 
144  BOOST_VERIFY(allHandlesSet);
145 
146  /// TODO(ahundt) use Ransac pivot calibration wrapper because there will likely be noise
147  TRTK::PivotCalibrationTwoStep<double> pivotCalib;
148  pivotCalib.setLocations(TRTK::make_range(tvecsArm));
149  pivotCalib.setRotations(TRTK::make_range(rvecsArm));
150 
151  /// TODO(ahundt) Allow selection of "TWO_STEP_PROECDURE" and "COMBINATORIAL_APPROACH" from V-REP LUA API
152  //pivotCalib.setAlgorithm("TWO_STEP_PROCEDURE");
153 
154  pivotCalib.compute();
155 
156  transformEstimate.translation() = pivotCalib.getPivotPoint();
157 
158 
159  // get fiducial in optical tracker base frame
160  int ret = simGetObjectPosition(toolTip, toolBase, detectedObjectPosition.begin());
161  if(ret==-1) BOOST_THROW_EXCEPTION(std::runtime_error("PivotCalibrationVrepPlugin: Could not get position"));
162  ret = simGetObjectQuaternion(toolTip, toolBase, detectedObjectQuaternion.begin());
163  if(ret==-1) BOOST_THROW_EXCEPTION(std::runtime_error("PivotCalibrationVrepPlugin: Could not get quaternion"));
164 
165  if(debug){
166  // print simulation transfrom from tip to fiducial
167  Eigen::Affine3d ToolTipToFiducial = getObjectTransform(toolTip,toolBase);
168  BOOST_LOG_TRIVIAL(info) << "\n" << poseString(ToolTipToFiducial,"expected ToolBaseToToolTip (simulation only): ") << std::endl;
169  }
170 
171  BOOST_LOG_TRIVIAL(info) << "\n" << poseString(transformEstimate,"estimated toolBaseMeasured to toolTipMeasured:") << std::endl;
172 
173  // print results
174  Eigen::Quaterniond eigenQuat(transformEstimate.rotation());
175  BOOST_LOG_TRIVIAL(info) << "Pivot Calibration Estimate quat wxyz\n: " << eigenQuat.w() << " " << eigenQuat.x() << " " << eigenQuat.y() << " " << eigenQuat.z() << " " << " translation xyz: " << transformEstimate.translation().x() << " " << transformEstimate.translation().y() << " " << transformEstimate.translation().z() << " " << std::endl;
176 
177  BOOST_LOG_TRIVIAL(info) << "Optical Tracker Base Measured quat wxyz\n: " << detectedObjectQuaternion[0] << " " << detectedObjectQuaternion[1] << " " << detectedObjectQuaternion[2] << " " << detectedObjectQuaternion[3] << " " << " translation xyz: " << detectedObjectPosition[0] << " " << detectedObjectPosition[1] << " " << detectedObjectPosition[2] << " " << std::endl;
178 
179 }
180 
181 /// @brief Will apply the stored estimate to the v-rep simulation value
182 ///
183 /// A default transform is saved when construct() was called
184 /// so if no estimate has been found that will be used.
186 
187  // set transform between end effector and fiducial
188  setObjectTransform(toolTipToModify, toolBaseToModify, transformEstimate);
189 }
190 
191 Eigen::Affine3d getEstimate(){
192  return transformEstimate;
193 }
194 
195 
196 /// @brief Correct modified transform for measured optical tracker data
197 ///
198 /// If real time transform measurements are happening applyEstimate will move the measured object
199 /// relative to the sensor and this puts the transform measurement back so the object
200 /// appears in its real position. However, if running in simulation only
201 /// the sensor will be in the correct position, so you don't want to call this.
203  // set real optical tracker position and orientation relative to the robot fiducial
204  simSetObjectPosition (toolTip, toolBase, detectedObjectPosition.begin());
205  simSetObjectQuaternion(toolTip, toolBase, detectedObjectQuaternion.begin());
206 }
207 
208 private:
209 
210 
211 
212 /// @todo create a function that calls simGetObjectHandle and throws an exception when it fails
213 /// @todo throw an exception if any of the handles is -1
214 void initHandles() {
215 
216  toolTip = grl::vrep::getHandleFromParam<ToolTipToMeasureName> (params_); //Obtain ToolTip handle
217  toolBase = grl::vrep::getHandleFromParam<ToolBaseToMeasureName> (params_);
218  toolTipToModify = grl::vrep::getHandleFromParam<ToolTipToModifyName> (params_); //Obtain ToolTip handle
219  toolBaseToModify = grl::vrep::getHandleFromParam<ToolBaseToModifyName> (params_);
220 
221  allHandlesSet = true;
222 }
223 
224 // TRTK::PivotCalibration<double>::Algorithm algorithm = TRTK::PivotCalibration<double>::Algorithm::TWO_STEP_PROCEDURE;
225 std::string algorithm = "TWO_STEP_PROCEDURE";
226 
227 std::vector<typename TRTK::PivotCalibrationTwoStep<double>::Matrix3T > rvecsArm;
228 std::vector<typename TRTK::PivotCalibrationTwoStep<double>::Vector3T > tvecsArm;
229 
230 bool isFirstFrame;
231 std::size_t frameCount;
232 Eigen::Affine3d firstToolTipInToolBaseInverse;
233 
234 ///
235 std::array<float,3> detectedObjectPosition;
236 std::array<float,4> detectedObjectQuaternion;
237 /// estimate transform between end effector and fiducial
238 Eigen::Affine3d transformEstimate;
239 
240 int toolTip = -1; //Obtain ToolTip handle
241 int toolBase = -1;
242 int toolTipToModify = -1;
243 int toolBaseToModify = -1;
244 //int ImplantCutPath = -1;
245 //int BallJointPath = -1;
246 //int bone = -1;
247 
248 bool allHandlesSet = false;
249 
250 
251 private:
252 Params params_;
253 
254 public:
255  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
256 };
257 
258 }
259 
260 #endif
void applyEstimate()
Will apply the stored estimate to the v-rep simulation value.
std::tuple< std::string, std::string, std::string, std::string > Params
void restoreSensorPosition()
Correct modified transform for measured optical tracker data.
V-REP handle string for the tip of the tool that will be measured
Eigen::Affine3d getObjectTransform(int objectHandle, int relativeToObjectHandle=-1)
Definition: Eigen.hpp:135
V-REP handle string for the base of the tool that will be modified
V-REP handle string for the tip of the tool that will be modified
ptrSimGetObjectPosition simGetObjectPosition
Definition: v_repLib.cpp:75
ptrSimSetObjectPosition simSetObjectPosition
Definition: v_repLib.cpp:76
void setAlgorithm(std::string algorithm_)
void setObjectTransform(int objectHandle, int relativeToObjectHandle, T &transform)
Definition: Eigen.hpp:117
void estimatePivotOffset()
run solver to estimate the unknown transform and set the simulation to the estimated value ...
ptrSimSetObjectQuaternion simSetObjectQuaternion
Definition: v_repLib.cpp:365
V-REP handle string for the base of the tool that will be measured
ptrSimGetObjectQuaternion simGetObjectQuaternion
Definition: v_repLib.cpp:364
PivotCalibrationVrepPlugin(Params params=defaultParams())