00001 #include "ros/param.h"
00002 #include "arm_3d_cb_calib/calib_3d_cbs.h"
00003
00004 using namespace std;
00005 using namespace gtsam;
00006
00007 namespace arm_3d_cb_calib {
00008
00009 void randomPoses(int num_poses, vector<Pose3>& poses, double radius=1.0)
00010 {
00011 boost::mt19937 rng;
00012 boost::uniform_real<> pt_range(-radius, radius);
00013 boost::uniform_real<> angle_range(0, M_PI);
00014 for(int i=0;i<num_poses;i++) {
00015 poses.push_back(Pose3(Rot3::ypr(angle_range(rng),angle_range(rng),angle_range(rng)),
00016 Point3(pt_range(rng),pt_range(rng),pt_range(rng))));
00017 }
00018 }
00019
00021
00022 void generateCBCalibProblem(CBCalibProblem& prob, CBCalibSolution& sol, int num_ees)
00023 {
00024 size_t num_kinects = prob.kinect_p_points.size();
00025 size_t num_cb_points = prob.cb_p_points.size();
00026 randomPoses(num_kinects, sol.kinect_T_base_poses, 10);
00027 vector<Pose3> offset_pose_;
00028 randomPoses(1, offset_pose_, 0.4);
00029 sol.cb_T_ee_pose = offset_pose_[0];
00030 randomPoses(num_ees, prob.base_T_ee_poses, 1.5);
00031
00032 for(size_t j=0;j<num_kinects;j++)
00033 for(size_t i=0;i<num_ees;i++) {
00034 prob.kinect_p_points[j].push_back(vector<Point3>());
00035 cout << (sol.kinect_T_base_poses[j] * prob.base_T_ee_poses[i] *
00036 sol.cb_T_ee_pose.inverse()).inverse().matrix() << endl;
00037 for(size_t l=0;l<num_cb_points;l++)
00038 prob.kinect_p_points[j][i].push_back(
00039 sol.kinect_T_base_poses[j] * prob.base_T_ee_poses[i] *
00040 sol.cb_T_ee_pose.inverse() * prob.cb_p_points[l]);
00041 }
00042 }
00043
00044 class CheckerboardArmFactor : public NoiseModelFactor2<Pose3, Pose3>
00045 {
00046 public:
00047 Point3 cb_p_point, kinect_p_point;
00048 Pose3 base_T_ee;
00049 CheckerboardArmFactor(const gtsam::SharedNoiseModel& noiseModel,
00050 Key j1, Key j2, Point3 _cb_p_point, Point3 _kinect_p_point,
00051 Pose3 _base_T_ee) :
00052 NoiseModelFactor2<Pose3, Pose3>(noiseModel, j1, j2),
00053 cb_p_point(_cb_p_point), kinect_p_point(_kinect_p_point), base_T_ee(_base_T_ee) {}
00054
00055 gtsam::Vector evaluateError(const gtsam::Pose3& cb_T_ee,
00056 const gtsam::Pose3& kinect_T_base,
00057 boost::optional<Matrix&> H_1 = boost::none,
00058 boost::optional<Matrix&> H_2 = boost::none) const
00059 {
00060 if(H_1) {
00061 (*H_1) = gtsam::Matrix_(3, 6);
00062 Point3 pt = cb_T_ee.inverse() * cb_p_point;
00063 Matrix cross = Matrix_(3,3,
00064 0.0,-pt.z(),pt.y(),
00065 pt.z(),0.0,-pt.x(),
00066 -pt.y(),pt.x(),0.0);
00067 (*H_1).block<3,3>(0,0) = base_T_ee.rotation().matrix() * cross;
00068 (*H_1).block<3,3>(0,3) = -base_T_ee.rotation().matrix();
00069 }
00070 if(H_2) {
00071 (*H_2) = gtsam::Matrix_(3, 6);
00072 Point3 pt = kinect_T_base.inverse() * kinect_p_point;
00073 Matrix cross = Matrix_(3,3,
00074 0.0,-pt.z(),pt.y(),
00075 pt.z(),0.0,-pt.x(),
00076 -pt.y(),pt.x(),0.0);
00077 (*H_2).block<3,3>(0,0) = -cross;
00078 (*H_2).block<3,3>(0,3) = gtsam::Rot3::yaw(0).matrix();
00079 }
00080 return (base_T_ee * cb_T_ee.inverse() * cb_p_point -
00081 kinect_T_base.inverse() * kinect_p_point).vector();
00082 }
00083 };
00084
00085 class PointTransFactor : public NoiseModelFactor1<Pose3>
00086 {
00087 public:
00088 Point3 cb_p_point, kinect_p_point;
00089 PointTransFactor(const gtsam::SharedNoiseModel& noiseModel,
00090 Key j1, Point3 _cb_p_point, Point3 _kinect_p_point) :
00091 NoiseModelFactor1<Pose3>(noiseModel, j1),
00092 cb_p_point(_cb_p_point), kinect_p_point(_kinect_p_point) {}
00093
00094 gtsam::Vector evaluateError(const gtsam::Pose3& cb_T_kinect,
00095 boost::optional<Matrix&> H_1 = boost::none) const
00096 {
00097 if(H_1) {
00098 (*H_1) = gtsam::Matrix_(3, 6);
00099 Point3 pt = cb_T_kinect.inverse() * cb_p_point;
00100 Matrix cross = Matrix_(3,3,
00101 0.0,-pt.z(),pt.y(),
00102 pt.z(),0.0,-pt.x(),
00103 -pt.y(),pt.x(),0.0);
00104 (*H_1).block<3,3>(0,0) = cross;
00105 (*H_1).block<3,3>(0,3) = -eye(3);
00106 }
00107 return (cb_T_kinect.inverse() * cb_p_point - kinect_p_point).vector();
00108 }
00109 };
00110
00111 class MultiPoseFactor : public NoiseModelFactor3<Pose3, Pose3, Pose3>
00112 {
00113 public:
00114 Pose3 base_T_ee;
00115 MultiPoseFactor(const gtsam::SharedNoiseModel& noiseModel,
00116 Key j1, Key j2, Key j3, Pose3 _base_T_ee) :
00117 NoiseModelFactor3<Pose3, Pose3, Pose3>(noiseModel, j1, j2, j3),
00118 base_T_ee(_base_T_ee) {}
00119
00120 gtsam::Vector evaluateError(const gtsam::Pose3& ee_T_cb,
00121 const gtsam::Pose3& kinect_T_base,
00122 const gtsam::Pose3& cb_T_kinect,
00123 boost::optional<Matrix&> H_1 = boost::none,
00124 boost::optional<Matrix&> H_2 = boost::none,
00125 boost::optional<Matrix&> H_3 = boost::none) const
00126 {
00127 if(H_1) {
00128 (*H_1) = (cb_T_kinect * kinect_T_base * base_T_ee * ee_T_cb).adjointMap();
00129 }
00130 if(H_2) {
00131 (*H_2) = (cb_T_kinect * kinect_T_base).adjointMap();
00132 }
00133 if(H_3) {
00134 (*H_3) = cb_T_kinect.adjointMap();
00135 }
00136 return Pose3::Logmap(cb_T_kinect * kinect_T_base * base_T_ee * ee_T_cb);
00137 }
00138 };
00139
00140 void solveCBCalibProblem(const CBCalibProblem& prob, CBCalibSolution& sol)
00141 {
00142 size_t num_kinects = prob.kinect_p_points.size();
00143 size_t num_cb_points = prob.cb_p_points.size();
00144
00145 double pt_noise, pose_noise;
00146 ros::param::param<double>("~pt_noise", pt_noise, 0.02);
00147 ros::param::param<double>("~pose_noise", pose_noise, 0.02);
00148 noiseModel::Isotropic::shared_ptr pt_fact_noise = noiseModel::Isotropic::Sigma(3, pt_noise);
00149 noiseModel::Isotropic::shared_ptr mp_fact_noise = noiseModel::Isotropic::Sigma(6, pose_noise);
00150
00151
00152
00153 gtsam::NonlinearFactorGraph graph;
00154 Values init_estimate;
00155
00156 bool init;
00157 double init_x, init_y, init_z, init_qx, init_qy, init_qz, init_qw;
00158 ros::param::param<bool>("~init", init, 0);
00159 ros::param::param<double>("~init_x", init_x, 0.0);
00160 ros::param::param<double>("~init_y", init_y, 0.0);
00161 ros::param::param<double>("~init_z", init_z, 0.0);
00162 ros::param::param<double>("~init_qx", init_qx, 0.0);
00163 ros::param::param<double>("~init_qy", init_qy, 0.0);
00164 ros::param::param<double>("~init_qz", init_qz, 0.0);
00165 ros::param::param<double>("~init_qw", init_qw, 1.0);
00166 int cb_ind = 0;
00167 Pose3 init_offset = Pose3(Quaternion(init_qw,init_qx,init_qy,init_qz),
00168 Point3(init_x,init_y,init_z));
00169 init_estimate.insert(Symbol('o',0), init_offset.inverse());
00170 if(init) {
00171 graph.add(boost::make_shared<PriorFactor<Pose3> >(
00172 Symbol('o',0), init_offset, mp_fact_noise));
00173 printf("*****************************************************\n%f %f %f %f %f %f %f\n", init_x, init_y, init_z, init_qx, init_qy, init_qz, init_qw);
00174 }
00175 for(size_t j=0;j<num_kinects;j++) {
00176 init_estimate.insert(Symbol('k',j), Pose3());
00177 for(size_t i=0;i<prob.kinect_p_points[j].size();i++) {
00178 init_estimate.insert(Symbol('c',cb_ind), Pose3());
00179
00180 graph.add(boost::make_shared<MultiPoseFactor>(
00181 mp_fact_noise,
00182 Symbol('o',0), Symbol('k',j), Symbol('c',cb_ind),
00183 prob.base_T_ee_poses[i]));
00184
00185 for(size_t l=0;l<num_cb_points;l++) {
00186 Point3 kinect_p = prob.kinect_p_points[j][i][l];
00187 if(kinect_p.x() != kinect_p.x())
00188 continue;
00189 graph.add(boost::make_shared<PointTransFactor>(
00190 pt_fact_noise,
00191 Symbol('c',cb_ind),
00192 prob.cb_p_points[l], kinect_p));
00193 }
00194 cb_ind++;
00195 }
00196 }
00197 Values result = DoglegOptimizer(graph, init_estimate).optimize();
00198 result.print();
00199 printf("start error: %f\n", graph.error(init_estimate));
00200 printf("end error: %f\n", graph.error(result));
00201 sol.cb_T_ee_pose = result.at<Pose3>(Symbol('o',0)).inverse();
00202 for(size_t j=0;j<num_kinects;j++)
00203 sol.kinect_T_base_poses.push_back(result.at<Pose3>(Symbol('k',j)));
00204 }
00205
00207
00208 geometry_msgs::Pose gtsamPose3ToGeomPose(const gtsam::Pose3& pose_in)
00209 {
00210 geometry_msgs::Pose pose_out;
00211 pose_out.position.x = pose_in.x();
00212 pose_out.position.y = pose_in.y();
00213 pose_out.position.z = pose_in.z();
00214 Quaternion q = pose_in.rotation().toQuaternion();
00215 pose_out.orientation.w = q.w();
00216 pose_out.orientation.x = q.x();
00217 pose_out.orientation.y = q.y();
00218 pose_out.orientation.z = q.z();
00219 return pose_out;
00220 }
00221
00222 gtsam::Pose3 geomPoseToGtsamPose3(const geometry_msgs::Pose& pose_in)
00223 {
00224 return gtsam::Pose3(Rot3(Quaternion(pose_in.orientation.w, pose_in.orientation.x,
00225 pose_in.orientation.y, pose_in.orientation.z)),
00226 Point3(pose_in.position.x, pose_in.position.y, pose_in.position.z));
00227 }
00228
00229 }