Visual Servoing Platform version 3.6.0
Loading...
Searching...
No Matches
tutorial-hand-eye-calibration.cpp
1
2#include <map>
3
4#include <visp3/core/vpIoTools.h>
5#include <visp3/vision/vpHandEyeCalibration.h>
6
7void usage(const char *argv [], int error)
8{
9 std::cout << "Synopsis" << std::endl
10 << " " << argv[0] << " [--data-path <path>] [--help] [-h]" << std::endl
11 << std::endl;
12 std::cout << "Description" << std::endl
13 << " --data-path <path> Path to the folder containing" << std::endl
14 << " pose_fPe_%d.yaml and pose_cPo_%d.yaml data files." << std::endl
15 << " Default: \"./\"" << std::endl
16 << std::endl
17 << " --fPe <generic name> Generic name of the yaml files" << std::endl
18 << " containing the pose of the end-effector expressed in the robot base" << std::endl
19 << " frame and located in the data path folder." << std::endl
20 << " Default: pose_fPe_%d.yaml" << std::endl
21 << std::endl
22 << " --cPo <generic name> Generic name of the yaml files" << std::endl
23 << " containing the pose of the calibration grid expressed in the camera" << std::endl
24 << " frame and located in the data path folder." << std::endl
25 << " Default: pose_cPo_%d.yaml" << std::endl
26 << std::endl
27 << " --output <filename> File in yaml format containing the pose of the camera" << std::endl
28 << " in the end-effector frame. Data are saved as a pose vector" << std::endl
29 << " with first the 3 translations along X,Y,Z in [m]" << std::endl
30 << " and then the 3 rotations in axis-angle representation (thetaU) in [rad]." << std::endl
31 << " Default: eMc.yaml" << std::endl
32 << std::endl
33 << " --help, -h Print this helper message." << std::endl
34 << std::endl;
35 if (error) {
36 std::cout << "Error" << std::endl
37 << " "
38 << "Unsupported parameter " << argv[error] << std::endl;
39 }
40}
41
42int main(int argc, const char *argv [])
43{
44 std::string opt_data_path = "./";
45 std::string opt_fPe_files = "pose_fPe_%d.yaml";
46 std::string opt_cPo_files = "pose_cPo_%d.yaml";
47 std::string opt_eMc_file = "eMc.yaml";
48
49 for (int i = 1; i < argc; i++) {
50 if (std::string(argv[i]) == "--data-path" && i + 1 < argc) {
51 opt_data_path = std::string(argv[i + 1]);
52 i++;
53 }
54 else if (std::string(argv[i]) == "--fPe" && i + 1 < argc) {
55 opt_fPe_files = std::string(argv[i + 1]);
56 i++;
57 }
58 else if (std::string(argv[i]) == "--cPo" && i + 1 < argc) {
59 opt_cPo_files = std::string(argv[i + 1]);
60 i++;
61 }
62 else if (std::string(argv[i]) == "--output" && i + 1 < argc) {
63 opt_eMc_file = std::string(argv[i + 1]);
64 i++;
65 }
66 else if (std::string(argv[i]) == "--help" || std::string(argv[i]) == "-h") {
67 usage(argv, 0);
68 return EXIT_SUCCESS;
69 }
70 else {
71 usage(argv, i);
72 return EXIT_FAILURE;
73 }
74 }
75
76 std::vector<vpHomogeneousMatrix> cMo;
77 std::vector<vpHomogeneousMatrix> wMe;
79
80 std::map<long, std::string> map_fPe_files;
81 std::map<long, std::string> map_cPo_files;
82 std::vector<std::string> files = vpIoTools::getDirFiles(opt_data_path);
83 for (unsigned int i = 0; i < files.size(); i++) {
84 long index_fPe = vpIoTools::getIndex(files[i], opt_fPe_files);
85 long index_cPo = vpIoTools::getIndex(files[i], opt_cPo_files);
86 if (index_fPe != -1) {
87 map_fPe_files[index_fPe] = files[i];
88 }
89 if (index_cPo != -1) {
90 map_cPo_files[index_cPo] = files[i];
91 }
92 }
93
94 if (map_fPe_files.size() == 0) {
95 std::cout << "No " << opt_fPe_files
96 << " files found. Use --data-path <path> or --fPe <generic name> be able to read your data." << std::endl;
97 return EXIT_FAILURE;
98 }
99 if (map_cPo_files.size() == 0) {
100 std::cout << "No " << opt_cPo_files
101 << " files found. Use --data-path <path> or --cPo <generic name> be able to read your data." << std::endl;
102 return EXIT_FAILURE;
103 }
104
105 for (std::map<long, std::string>::const_iterator it_fPe = map_fPe_files.begin(); it_fPe != map_fPe_files.end();
106 ++it_fPe) {
107 std::string file_fPe = vpIoTools::createFilePath(opt_data_path, it_fPe->second);
108 std::map<long, std::string>::const_iterator it_cPo = map_cPo_files.find(it_fPe->first);
109 if (it_cPo != map_cPo_files.end()) {
110 vpPoseVector wPe;
111 if (wPe.loadYAML(file_fPe, wPe) == false) {
112 std::cout << "Unable to read data from " << file_fPe << ". Skip data" << std::endl;
113 continue;
114 }
115
116 vpPoseVector cPo;
117 std::string file_cPo = vpIoTools::createFilePath(opt_data_path, it_cPo->second);
118 if (cPo.loadYAML(file_cPo, cPo) == false) {
119 std::cout << "Unable to read data from " << file_cPo << ". Skip data" << std::endl;
120 continue;
121 }
122 std::cout << "Use data from " << opt_data_path << "/" << file_fPe << " and from " << file_cPo << std::endl;
123 wMe.push_back(vpHomogeneousMatrix(wPe));
124 cMo.push_back(vpHomogeneousMatrix(cPo));
125 }
126 }
127
128 if (wMe.size() < 3) {
129 std::cout << "Not enough data pairs found." << std::endl;
130 return EXIT_FAILURE;
131 }
132
133 int ret = vpHandEyeCalibration::calibrate(cMo, wMe, eMc);
134
135 if (ret == 0) {
136 std::cout << std::endl << "** Hand-eye calibration succeed" << std::endl;
137 std::cout << std::endl << "** Hand-eye (eMc) transformation estimated:" << std::endl;
138 std::cout << eMc << std::endl;
139 std::cout << "** Corresponding pose vector [tx ty tz tux tuy tuz] in [m] and [rad]: " << vpPoseVector(eMc).t() << std::endl;
140
142 std::cout << std::endl << "** Translation [m]: " << eMc[0][3] << " " << eMc[1][3] << " " << eMc[2][3] << std::endl;
143 std::cout << "** Rotation (theta-u representation) [rad]: " << erc.t() << std::endl;
144 std::cout << "** Rotation (theta-u representation) [deg]: " << vpMath::deg(erc[0]) << " " << vpMath::deg(erc[1])
145 << " " << vpMath::deg(erc[2]) << std::endl;
146 vpQuaternionVector quaternion(eMc.getRotationMatrix());
147 std::cout << "** Rotation (quaternion representation) [rad]: " << quaternion.t() << std::endl;
149 std::cout << "** Rotation (r-x-y-z representation) [rad]: " << rxyz.t() << std::endl;
150 std::cout << "** Rotation (r-x-y-z representation) [deg]: " << vpMath::deg(rxyz).t() << std::endl;
151
152 // save eMc
153 std::string name_we = vpIoTools::createFilePath(vpIoTools::getParent(opt_eMc_file), vpIoTools::getNameWE(opt_eMc_file)) + ".txt";
154 std::cout << std::endl << "Save transformation matrix eMc as an homogeneous matrix in: " << name_we << std::endl;
155#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
156 std::ofstream file_eMc(name_we);
157#else
158 std::ofstream file_eMc(name_we.c_str());
159#endif
160 eMc.save(file_eMc);
161
162 vpPoseVector pose_vec(eMc);
163 std::string output_filename = vpIoTools::createFilePath(vpIoTools::getParent(opt_eMc_file), vpIoTools::getName(opt_eMc_file));
164 std::cout << "Save transformation matrix eMc as a vpPoseVector in : " << output_filename << std::endl;
165 pose_vec.saveYAML(output_filename, pose_vec);
166 }
167 else {
168 std::cout << std::endl << "** Hand-eye calibration failed" << std::endl;
169 std::cout << std::endl << "Check your input data and ensure they are covering the half sphere over the chessboard." << std::endl;
170 std::cout << std::endl << "See https://visp-doc.inria.fr/doxygen/visp-daily/tutorial-calibration-extrinsic.html" << std::endl;
171 }
172
173 return EXIT_SUCCESS;
174}
vpArray2D< Type > t() const
Compute the transpose of the array.
Definition vpArray2D.h:1059
static bool loadYAML(const std::string &filename, vpArray2D< Type > &A, char *header=NULL)
Definition vpArray2D.h:696
static int calibrate(const std::vector< vpHomogeneousMatrix > &cMo, const std::vector< vpHomogeneousMatrix > &rMe, vpHomogeneousMatrix &eMc)
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpRotationMatrix getRotationMatrix() const
void save(std::ofstream &f) const
static long getIndex(const std::string &filename, const std::string &format)
static std::string createFilePath(const std::string &parent, const std::string &child)
static std::vector< std::string > getDirFiles(const std::string &dirname)
static std::string getNameWE(const std::string &pathname)
static std::string getParent(const std::string &pathname)
static std::string getName(const std::string &pathname)
static double deg(double rad)
Definition vpMath.h:106
Implementation of a pose vector and operations on poses.
vpRowVector t() const
Implementation of a rotation vector as quaternion angle minimal representation.
Implementation of a rotation vector as Euler angle minimal representation.
Implementation of a rotation vector as axis-angle minimal representation.