国产免费AV|泡泡玛特欧洲总部将设在伦敦|中文天堂网www新版资源在线|一本久道综合在线中文|国精产品一二三产区的使用方法|香蕉鱼在线观看|www.27eee

 找回密碼
 注冊
搜索

VC2017+OPENCV4.30實(shí)現(xiàn)機(jī)器人與傳感器的手眼標(biāo)定,親測可用

[復(fù)制鏈接]
樓主
Leonarad 發(fā)表于 2021-4-8 00:57:01 | 只看該作者 |倒序?yàn)g覽 |閱讀模式
使用VC2017結(jié)合OPENCV4.30實(shí)現(xiàn)機(jī)器人坐標(biāo)系與傳感器坐標(biāo)系的手眼標(biāo)定。可以計(jì)算出機(jī)器人的工具坐標(biāo)系和傳感器坐標(biāo)系的相對位置關(guān)系矩陣。自己親自測試,好用。
  1. // HandEyeCalibrationTest.cpp : 此文件包含 "main" 函數(shù)。程序執(zhí)行將在此處開始并結(jié)束。
  2. //
  3. #include <opencv2/opencv.hpp>
  4. #include <iostream>
  5. #include <math.h>

  6. //#pragma comment( lib, "opencv_world430.lib" )

  7. using namespace std;
  8. using namespace cv;

  9. Mat R_T2HomogeneousMatrix(const Mat& R, const Mat& T);
  10. void HomogeneousMtr2RT(Mat& HomoMtr, Mat& R, Mat& T);
  11. bool isRotatedMatrix(Mat& R);
  12. Mat eulerAngleToRotateMatrix(const Mat& eulerAngle, const std::string& seq);
  13. Mat quaternionToRotatedMatrix(const Vec4d& q);
  14. Mat attitudeVectorToMatrix(const Mat& m, bool useQuaternion, const string& seq);
  15. //數(shù)據(jù)使用的已有的值
  16. //相機(jī)中13組標(biāo)定板的位姿,x,y,z,rx,ry,rz,
  17. Mat_<double> CalPose = (cv::Mat_<double>(9, 6) <<
  18.         -2.602917e+01, -2.058909e+01, 2.001158e+02, -2.222308e+00, -2.200891e+00, 1.038314e-02,
  19.         -2.109788e+01, -1.966766e+01, 1.820841e+02, 2.145852e+00, 2.143222e+00, 3.322979e-01,
  20.         -2.571942e+01, -1.872411e+01, 2.013287e+02, -2.108920e+00, -2.134951e+00, 1.931600e-01,
  21.         -2.488133e+01, -1.828509e+01, 1.956522e+02, -2.047373e+00, -2.027428e+00, 4.624128e-02,
  22.         -2.920918e+01, -2.170171e+01, 2.143397e+02, 2.174664e+00, 2.123216e+00, -1.765171e-01,
  23.         -2.518449e+01, -1.630078e+01, 2.110271e+02, 2.229811e+00, 2.162015e+00, -2.832562e-01,
  24.         -2.729219e+01, -1.855265e+01, 1.884390e+02, -2.130600e+00, -2.041023e+00, 2.669174e-02,
  25.         -2.754954e+01, -1.465493e+01, 1.886429e+02, -2.204029e+00, -2.089585e+00, -1.583544e-01,
  26.         -2.716471e+01, -1.718814e+01, 1.924382e+02, -2.287743e+00, -2.088326e+00, -2.886300e-01);

  27. //機(jī)械臂末端13組位姿,x,y,z,rx,ry,rz
  28. Mat_<double> ToolPose = (cv::Mat_<double>(9, 6) <<
  29.         1437.754, 385.919, 40.011, -8.792, 18.557, -17.376,
  30.         1437.714, 387.617, 34.178, -23.661, 16.950, -21.540,
  31.         1440.563, 382.431, 36.997, 0.829, 22.108, -12.817,
  32.         1440.555, 385.317, 45.598, -1.599, 30.965, -14.361,
  33.         1433.627, 385.860, 37.482, -4.907, 10.576, -16.978,
  34.         1439.363, 390.483, 34.553, 0.388, 13.051, -15.847,
  35.         1438.171, 387.592, 36.215, -4.281, 27.707, -17.485,
  36.         1442.171, 388.187, 41.308, -13.644, 25.154, -21.693,
  37.         1439.222, 392.200, 48.119, -19.865, 22.540, -25.981);

  38. int main(int argc, char** argv)
  39. {
  40.         //數(shù)據(jù)聲明
  41.         vector<Mat> R_gripper2base;
  42.         vector<Mat> T_gripper2base;
  43.         vector<Mat> R_target2cam;
  44.         vector<Mat> T_target2cam;
  45.         Mat R_cam2gripper = Mat(3, 3, CV_64FC1);                                //相機(jī)與機(jī)械臂末端坐標(biāo)系的旋轉(zhuǎn)矩陣與平移矩陣
  46.         Mat T_cam2gripper = Mat(3, 1, CV_64FC1);
  47.         Mat Homo_cam2gripper = Mat(4, 4, CV_64FC1);

  48.         vector<Mat> Homo_target2cam;
  49.         vector<Mat> Homo_gripper2base;
  50.         Mat tempR, tempT, temp;

  51.         for (int i = 0; i < CalPose.rows; i++)                                //計(jì)算標(biāo)定板與相機(jī)間的齊次矩陣(旋轉(zhuǎn)矩陣與平移向量)
  52.         {
  53.                 temp = attitudeVectorToMatrix(CalPose.row(i), false, "");        //注意seq為空,相機(jī)與標(biāo)定板間的為旋轉(zhuǎn)向量
  54.                 Homo_target2cam.push_back(temp);
  55.                 HomogeneousMtr2RT(temp, tempR, tempT);
  56.                 /*cout << i << "::" << temp << endl;
  57.                 cout << i << "::" << tempR << endl;
  58.                 cout << i << "::" << tempT << endl;*/
  59.                 R_target2cam.push_back(tempR);
  60.                 T_target2cam.push_back(tempT);
  61.         }
  62.         for (int j = 0; j < ToolPose.rows; j++)                                //計(jì)算機(jī)械臂末端坐標(biāo)系與機(jī)器人基坐標(biāo)系之間的齊次矩陣
  63.         {
  64.                 temp = attitudeVectorToMatrix(ToolPose.row(j), false, "xyz");  //注意seq不是空,機(jī)械臂末端坐標(biāo)系與機(jī)器人基坐標(biāo)系之間的為歐拉角
  65.                 Homo_gripper2base.push_back(temp);
  66.                 HomogeneousMtr2RT(temp, tempR, tempT);
  67.                 /*cout << j << "::" << temp << endl;
  68.                 cout << j << "::" << tempR << endl;
  69.                 cout << j << "::" << tempT << endl;*/
  70.                 R_gripper2base.push_back(tempR);
  71.                 T_gripper2base.push_back(tempT);
  72.         }
  73.         //TSAI計(jì)算速度最快
  74.         calibrateHandEye(R_gripper2base, T_gripper2base, R_target2cam, T_target2cam, R_cam2gripper, T_cam2gripper, CALIB_HAND_EYE_TSAI);

  75.         Homo_cam2gripper = R_T2HomogeneousMatrix(R_cam2gripper, T_cam2gripper);
  76.         cout << Homo_cam2gripper << endl;
  77.         cout << "Homo_cam2gripper 是否包含旋轉(zhuǎn)矩陣:" << isRotatedMatrix(Homo_cam2gripper) << endl;

  78.         FileStorage fs(".\\Homo_cam2gripper.xml", FileStorage::WRITE);
  79.         fs << "Homo_cam2gripper" << Homo_cam2gripper;
  80.         fs.release();

  81.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////

  82.         /**************************************************
  83.         * @note   手眼系統(tǒng)精度測試,原理是標(biāo)定板在機(jī)器人基坐標(biāo)系中位姿固定不變,
  84.         *                  可以根據(jù)這一點(diǎn)進(jìn)行演算
  85.         **************************************************/
  86.         //使用1,2組數(shù)據(jù)驗(yàn)證  標(biāo)定板在機(jī)器人基坐標(biāo)系中位姿固定不變
  87.         cout << "1 : " << Homo_gripper2base[0] * Homo_cam2gripper * Homo_target2cam[0] << endl;
  88.         cout << "2 : " << Homo_gripper2base[1] * Homo_cam2gripper * Homo_target2cam[1] << endl;
  89.         //標(biāo)定板在相機(jī)中的位姿
  90.         cout << "3 : " << Homo_target2cam[1] << endl;
  91.         cout << "4 : " << Homo_cam2gripper.inv() * Homo_gripper2base[1].inv() * Homo_gripper2base[0] * Homo_cam2gripper * Homo_target2cam[0] << endl;

  92.         cout << "----手眼系統(tǒng)測試-----" << endl;
  93.         cout << "機(jī)械臂下標(biāo)定板XYZ為:" << endl;
  94.         for (size_t i = 0; i < Homo_target2cam.size(); i++)
  95.         {
  96.                 Mat chessPos{ 0.0,0.0,0.0,1.0 };  //4*1矩陣,單獨(dú)求機(jī)械臂坐標(biāo)系下,標(biāo)定板XYZ
  97.                 Mat worldPos = Homo_gripper2base[i] * Homo_cam2gripper * Homo_target2cam[i] * chessPos;
  98.                 cout << i << ": " << worldPos.t() << endl;
  99.         }
  100.         waitKey(0);

  101.         return 0;
  102. }

  103. /**************************************************
  104. * @brief   將旋轉(zhuǎn)矩陣與平移向量合成為齊次矩陣
  105. * @note
  106. * @param   Mat& R   3*3旋轉(zhuǎn)矩陣
  107. * @param   Mat& T   3*1平移矩陣
  108. * @return  Mat      4*4齊次矩陣
  109. **************************************************/
  110. Mat R_T2HomogeneousMatrix(const Mat& R, const Mat& T)
  111. {
  112.         Mat HomoMtr;
  113.         Mat_<double> R1 = (Mat_<double>(4, 3) <<
  114.                 R.at<double>(0, 0), R.at<double>(0, 1), R.at<double>(0, 2),
  115.                 R.at<double>(1, 0), R.at<double>(1, 1), R.at<double>(1, 2),
  116.                 R.at<double>(2, 0), R.at<double>(2, 1), R.at<double>(2, 2),
  117.                 0, 0, 0);
  118.         Mat_<double> T1 = (Mat_<double>(4, 1) <<
  119.                 T.at<double>(0, 0),
  120.                 T.at<double>(1, 0),
  121.                 T.at<double>(2, 0),
  122.                 1);
  123.         cv::hconcat(R1, T1, HomoMtr);                //矩陣拼接
  124.         return HomoMtr;
  125. }

  126. /**************************************************
  127. * @brief    齊次矩陣分解為旋轉(zhuǎn)矩陣與平移矩陣
  128. * @note
  129. * @param        const Mat& HomoMtr  4*4齊次矩陣
  130. * @param        Mat& R              輸出旋轉(zhuǎn)矩陣
  131. * @param        Mat& T                                輸出平移矩陣
  132. * @return
  133. **************************************************/
  134. void HomogeneousMtr2RT(Mat& HomoMtr, Mat& R, Mat& T)
  135. {
  136.         //Mat R_HomoMtr = HomoMtr(Rect(0, 0, 3, 3)); //注意Rect取值
  137.         //Mat T_HomoMtr = HomoMtr(Rect(3, 0, 1, 3));
  138.         //R_HomoMtr.copyTo(R);
  139.         //T_HomoMtr.copyTo(T);
  140.         /*HomoMtr(Rect(0, 0, 3, 3)).copyTo(R);
  141.         HomoMtr(Rect(3, 0, 1, 3)).copyTo(T);*/
  142.         Rect R_rect(0, 0, 3, 3);
  143.         Rect T_rect(3, 0, 1, 3);
  144.         R = HomoMtr(R_rect);
  145.         T = HomoMtr(T_rect);

  146. }

  147. /**************************************************
  148. * @brief        檢查是否是旋轉(zhuǎn)矩陣
  149. * @note
  150. * @param
  151. * @param
  152. * @param
  153. * @return  true : 是旋轉(zhuǎn)矩陣, false : 不是旋轉(zhuǎn)矩陣
  154. **************************************************/
  155. bool isRotatedMatrix(Mat& R)                //旋轉(zhuǎn)矩陣的轉(zhuǎn)置矩陣是它的逆矩陣,逆矩陣 * 矩陣 = 單位矩陣
  156. {
  157.         Mat temp33 = R({ 0,0,3,3 });        //無論輸入是幾階矩陣,均提取它的三階矩陣
  158.         Mat Rt;
  159.         transpose(temp33, Rt);  //轉(zhuǎn)置矩陣
  160.         Mat shouldBeIdentity = Rt * temp33;//是旋轉(zhuǎn)矩陣則乘積為單位矩陣
  161.         Mat I = Mat::eye(3, 3, shouldBeIdentity.type());

  162.         return cv::norm(I, shouldBeIdentity) < 1e-6;
  163. }

  164. /**************************************************
  165. * @brief   歐拉角轉(zhuǎn)換為旋轉(zhuǎn)矩陣
  166. * @note
  167. * @param    const std::string& seq  指定歐拉角的排列順序;(機(jī)械臂的位姿類型有xyz,zyx,zyz幾種,需要區(qū)分)
  168. * @param    const Mat& eulerAngle   歐拉角(1*3矩陣), 角度值
  169. * @param
  170. * @return   返回3*3旋轉(zhuǎn)矩陣
  171. **************************************************/
  172. Mat eulerAngleToRotateMatrix(const Mat& eulerAngle, const std::string& seq)
  173. {
  174.         CV_Assert(eulerAngle.rows == 1 && eulerAngle.cols == 3);//檢查參數(shù)是否正確

  175.         eulerAngle /= (180 / CV_PI);                //度轉(zhuǎn)弧度

  176.         Matx13d m(eulerAngle);                                //<double, 1, 3>

  177.         auto rx = m(0, 0), ry = m(0, 1), rz = m(0, 2);
  178.         auto rxs = sin(rx), rxc = cos(rx);
  179.         auto rys = sin(ry), ryc = cos(ry);
  180.         auto rzs = sin(rz), rzc = cos(rz);

  181.         //XYZ方向的旋轉(zhuǎn)矩陣
  182.         Mat RotX = (Mat_<double>(3, 3) << 1, 0, 0,
  183.                 0, rxc, -rxs,
  184.                 0, rxs, rxc);
  185.         Mat RotY = (Mat_<double>(3, 3) << ryc, 0, rys,
  186.                 0, 1, 0,
  187.                 -rys, 0, ryc);
  188.         Mat RotZ = (Mat_<double>(3, 3) << rzc, -rzs, 0,
  189.                 rzs, rzc, 0,
  190.                 0, 0, 1);
  191.         //按順序合成后的旋轉(zhuǎn)矩陣
  192.         cv::Mat rotMat;

  193.         if (seq == "zyx") rotMat = RotX * RotY * RotZ;
  194.         else if (seq == "yzx") rotMat = RotX * RotZ * RotY;
  195.         else if (seq == "zxy") rotMat = RotY * RotX * RotZ;
  196.         else if (seq == "yxz") rotMat = RotZ * RotX * RotY;
  197.         else if (seq == "xyz") rotMat = RotZ * RotY * RotX;
  198.         else if (seq == "xzy") rotMat = RotY * RotZ * RotX;
  199.         else
  200.         {
  201.                 cout << "Euler Angle Sequence string is wrong...";
  202.         }
  203.         if (!isRotatedMatrix(rotMat))                //歐拉角特殊情況下會(huì)出現(xiàn)死鎖
  204.         {
  205.                 cout << "Euler Angle convert to RotatedMatrix failed..." << endl;
  206.                 exit(-1);
  207.         }
  208.         return rotMat;
  209. }

  210. /**************************************************
  211. * @brief   將四元數(shù)轉(zhuǎn)換為旋轉(zhuǎn)矩陣
  212. * @note
  213. * @param   const Vec4d& q   歸一化的四元數(shù): q = q0 + q1 * i + q2 * j + q3 * k;
  214. * @return  返回3*3旋轉(zhuǎn)矩陣R
  215. **************************************************/
  216. Mat quaternionToRotatedMatrix(const Vec4d& q)
  217. {
  218.         double q0 = q[0], q1 = q[1], q2 = q[2], q3 = q[3];

  219.         double q0q0 = q0 * q0, q1q1 = q1 * q1, q2q2 = q2 * q2, q3q3 = q3 * q3;
  220.         double q0q1 = q0 * q1, q0q2 = q0 * q2, q0q3 = q0 * q3;
  221.         double q1q2 = q1 * q2, q1q3 = q1 * q3;
  222.         double q2q3 = q2 * q3;
  223.         //根據(jù)公式得來
  224.         Mat RotMtr = (Mat_<double>(3, 3) << (q0q0 + q1q1 - q2q2 - q3q3), 2 * (q1q2 + q0q3), 2 * (q1q3 - q0q2),
  225.                 2 * (q1q2 - q0q3), (q0q0 - q1q1 + q2q2 - q3q3), 2 * (q2q3 + q0q1),
  226.                 2 * (q1q3 + q0q2), 2 * (q2q3 - q0q1), (q0q0 - q1q1 - q2q2 + q3q3));
  227.         //這種形式等價(jià)
  228.         /*Mat RotMtr = (Mat_<double>(3, 3) << (1 - 2 * (q2q2 + q3q3)), 2 * (q1q2 - q0q3), 2 * (q1q3 + q0q2),
  229.                                                                                  2 * (q1q2 + q0q3), 1 - 2 * (q1q1 + q3q3), 2 * (q2q3 - q0q1),
  230.                                                                                  2 * (q1q3 - q0q2), 2 * (q2q3 + q0q1), (1 - 2 * (q1q1 + q2q2)));*/

  231.         return RotMtr;
  232. }

  233. /**************************************************
  234. * @brief      將采集的原始數(shù)據(jù)轉(zhuǎn)換為齊次矩陣(從機(jī)器人控制器中獲得的)
  235. * @note
  236. * @param          Mat& m    1*6//1*10矩陣 , 元素為: x,y,z,rx,ry,rz  or x,y,z, q0,q1,q2,q3,rx,ry,rz
  237. * @param          bool useQuaternion      原始數(shù)據(jù)是否使用四元數(shù)表示
  238. * @param          string& seq         原始數(shù)據(jù)使用歐拉角表示時(shí),坐標(biāo)系的旋轉(zhuǎn)順序
  239. * @return          返回轉(zhuǎn)換完的齊次矩陣
  240. **************************************************/
  241. Mat attitudeVectorToMatrix(const Mat& m, bool useQuaternion, const string& seq)
  242. {
  243.         CV_Assert(m.total() == 6 || m.total() == 10);
  244.         //if (m.cols == 1)        //轉(zhuǎn)置矩陣為行矩陣
  245.         //        m = m.t();        

  246.         Mat temp = Mat::eye(4, 4, CV_64FC1);

  247.         if (useQuaternion)
  248.         {
  249.                 Vec4d quaternionVec = m({ 3,0,4,1 });   //讀取存儲(chǔ)的四元數(shù)
  250.                 quaternionToRotatedMatrix(quaternionVec).copyTo(temp({ 0,0,3,3 }));
  251.         }
  252.         else
  253.         {
  254.                 Mat rotVec;
  255.                 if (m.total() == 6)
  256.                 {
  257.                         rotVec = m({ 3,0,3,1 });   //讀取存儲(chǔ)的歐拉角
  258.                 }
  259.                 if (m.total() == 10)
  260.                 {
  261.                         rotVec = m({ 7,0,3,1 });
  262.                 }
  263.                 //如果seq為空,表示傳入的是3*1旋轉(zhuǎn)向量,否則,傳入的是歐拉角
  264.                 if (0 == seq.compare(""))
  265.                 {
  266.                         Rodrigues(rotVec, temp({ 0,0,3,3 }));   //羅德利斯轉(zhuǎn)換
  267.                 }
  268.                 else
  269.                 {
  270.                         eulerAngleToRotateMatrix(rotVec, seq).copyTo(temp({ 0,0,3,3 }));
  271.                 }
  272.         }
  273.         //存入平移矩陣
  274.         temp({ 3,0,1,3 }) = m({ 0,0,3,1 }).t();
  275.         return temp;   //返回轉(zhuǎn)換結(jié)束的齊次矩陣
  276. }
復(fù)制代碼
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則

手機(jī)版|小黑屋|ELEOK |網(wǎng)站地圖

GMT+8, 2026-5-26 02:08

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

快速回復(fù) 返回頂部 返回列表