日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ROS中使用Eigen库[不定期更新]

發(fā)布時(shí)間:2024/4/18 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ROS中使用Eigen库[不定期更新] 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前期說明

ROS中的數(shù)據(jù)操作需要線性代數(shù),Eigen庫是C++中的線性代數(shù)計(jì)算庫。
Eigen庫獨(dú)立于ROS,但是在ROS中可以使用。
Eigen庫可以參見http://eigen.tuxfamily.org

在ROS中配置Eigen

在CMakeLists.txt文件中要做以下配置

#uncomment the following 4 lines to use the Eigen library find_package(cmake_modules REQUIRED) find_package(Eigen3 REQUIRED) include_directories(${EIGEN3_INCLUDE_DIR}) add_definitions(${EIGEN_DEFINITIONS})

源碼中要包含以下文件:

#include <Eigen/Eigen> #include <Eigen/Dense> #include <Eigen/Geometry> #include <Eigen/Eigenvalues>

如果需要使用其他的功能,可以包含更多的頭文件。
參見這個(gè)網(wǎng)址http://eigen.tuxfamily.org/dox/group__QuickRefPage.html#QuickRef_Headers

簡單實(shí)例

  • 定義一個(gè)向量:
  • // here is an arbitrary normal vector // initialized to (1,2,3) upon instantiation Eigen::Vector3d normal_vec(1,2,3);

    將實(shí)例化一個(gè)Eigen對象,它是由3個(gè)雙精度值組成的列向量. 該對象命名為normal_vec,初始化值為(1,2,3).

  • 將向量變成單位向量
  • // make this vector unit length normal_vec/=normal_vec.norm();

    這里使用了Eigen::Vector3d的一個(gè)成員函數(shù)norm(),用以計(jì)算向量的歐幾里得長度.如果normal_vec是一個(gè)非零向量,可以用norm()函數(shù)直接求其長度.

  • 定義一個(gè)矩陣的形式:
    • 可以按行賦值,一行一行地用數(shù)據(jù)生成矩陣。
    Eigen::Matrix3d Rot_z; Rot_z.row(0)<<0,-1, 0; // populate the first row--shorthand method Rot_z.row(1)<<1, 0, 0; // second row Rot_z.row(2)<<0, 0, 1; // yada, yada cout<<"Rot_z: "<<endl;
    • 還有很多其他方法用于初始化或生成矩陣和向量.例如,用戶可以用零來生成一個(gè)向量或矩陣.其中參數(shù)(3,1)指定了3行1列.(向量是特殊的矩陣,不是一行就是一列)
    // first compute the centroid of the data: // here's a handy way to initialize data to all zeros; more variants exist // see http://eigen.tuxfamily.org/dox/AsciiQuickReference.txt Eigen::Vector3d centroid = Eigen::MatrixXd::Zero(3,1);
    • 用戶可以在實(shí)例化的時(shí)候?qū)⒊跏贾抵付闃?gòu)造函數(shù)的參數(shù).將向量初始化為1:
    //xxxx one_vec*dist = point.dot(nx,ny,nz) // so, one_vec = points_mat.transpose()*x_vec, where x_vec = [nx;ny;nz]/dist (does not work if dist=0) // this is of the form: b = A*x, an overdetermined system of eqns // solve this using one of many Eigen methods // see: http://eigen.tuxfamily.org/dox/group__TutorialLinearAlgebra.html ROS_INFO("2ND APPROACH b = A*x SOLN"); Eigen::VectorXd ones_vec= Eigen::MatrixXd::Ones(npts,1); // this is our "b" vector in b = A*x
  • 矩陣與向量的乘法
  • //here is how to multiply a matrix times a vector //although Rot_z and normal_vec are both objects (with associated data and member methods) //multiplication is defined, //resulting in the data members being altered or generated as expected for matrix-vector multiplies v1 = Rot_z*normal_vec;

    示例代碼

    // wsn: program to illustrate use of Eigen library to fit a plane to a collection of points#include<ros/ros.h>#include <fstream> #include <iostream> #include <sstream> #include <string> #include <vector>#include <Eigen/Eigen> #include <Eigen/Dense> #include <Eigen/Geometry> #include <Eigen/Eigenvalues>using namespace std; //using namespace Eigen; //if you get tired of typing Eigen:: everywhere, uncomment this.// but I'll leave this as required, for now, to highlight when Eigen classes are being useddouble g_noise_gain = 0.1; //0.1; //0.1; //0.1; //decide how much noise to add to points; start with 0.0, and should get precise resultsint main(int argc, char** argv) {ros::init(argc, argv, "example_eigen_plane_fit"); //node nameros::NodeHandle nh; // create a node handle; need to pass this to the class constructorros::Rate sleep_timer(1.0); //a timer for desired rate, e.g. 1Hz//xxxxxxxxxxxxxxxxxx THIS PART IS JUST TO GENERATE DATA xxxxxxxxxxxxxxxxxxxx//xxxxxxxxxxxxxxxxxx NORMALLY, THIS DATA WOULD COME FROM TOPICS OR FROM GOALS xxxxxxxxx// define a plane and generate some points on that plane// the plane can be defined in terms of a normal vector and a distance from the originEigen::Vector3d normal_vec(1,2,3); // here is an arbitrary normal vector, initialized to (1,2,3) upon instantiationROS_INFO("creating example noisy, planar data...");cout<<"normal: "<<normal_vec.transpose()<<endl; //.transpose() is so I can display the components on the same line, instead of as a columnnormal_vec/=normal_vec.norm(); // make this vector unit lengthcout<<"unit length normal: "<<normal_vec.transpose()<<endl;double dist = 1.23; // define the plane to have this distance from the origin. Note that if we care about positive/negative sides of a plane,// then this "distance" could be negative, as measured from the origin to the plane along the positive plane normalcout<<"plane distance from origin: "<<dist<<endl;// to generate points on the plane, construct a pair of axes perpendicular to the plane normalEigen::Vector3d v1,v2; //need to fill in values for these// we'll use an Eigen "Matrix" type to help out. Define a 3x3 "double precision" matrix, Matrix3d//define a rotation about the z axis of 90 deg; elements of this matrix are:// [0,-1,0; // 1, 0, 0; // 0;0;1]Eigen::Matrix3d Rot_z;Rot_z.row(0)<<0,-1,0; // populate the first row--shorthand methodRot_z.row(1)<<1, 0,0; //second rowRot_z.row(2)<<0, 0,1; // yada, yadacout<<"Rot_z: "<<endl; cout<<Rot_z<<endl; // Eigen matrices and vectors are nicely formatted; better: use ROS_INFO_STREAM() instead of coutROS_INFO_STREAM(endl<<Rot_z);// we need another vector to generate two desired vectors in our plane.// start by generating a new vector that is a rotation of our normal vector, rotated about the z-axis// this hack will NOT work if our normal_vec = [0,0,1], v1 = Rot_z*normal_vec; //here is how to multiply a matrix times a vector//although Rot_z and normal_vec are both objects (with associated data and member methods), multiplication is defined,// resulting in the data members being altered or generated as expected for matrix-vector multipliesROS_INFO_STREAM("v1: "<<v1.transpose()<<endl);// let's look at the dot product between v1 and normal_vec, using two approachesdouble dotprod = v1.dot(normal_vec); //using the "dot()" member functiondouble dotprod2 = v1.transpose()*normal_vec;// alt: turn v1 into a row vector, then multiply times normal_veccout<<"v1 dot normal: "<<dotprod<<"; v1.transpose()*normal_vec: "<<dotprod2<<endl; //yields the same answercout<<"(should be identical)"<<endl;// let's look at the cross product, v1 X normal_vec; use the member fnc cross()v2 = v1.cross(normal_vec);v2/=v2.norm(); // normalize the output, i.e. make v2 unit lengthcout<<"v2: "<<v2.transpose()<<endl;//because v2 was generated from the cross product of v1 and normal_vec, it should be perpendicular to both// i.e., the dot product with v1 or normal_vec should be = 0dotprod = v2.dot(normal_vec);cout<<"v2 dot normal_vec = "<<dotprod<<" (should be zero)"<<endl;v1 = v2.cross(normal_vec); // re-use v1; make it the cross product of v2 into normal_vec// thus, v1 should now also be perpendicular to normal_vec (and thus it is parallel to our plane)// and also perpendicular to v2 (so both v1 and v2 lie in the plane and are perpendicular to each other)cout<<"v1= "<<v1.transpose()<<endl;cout<<" v1 dot v2 = "<<v1.dot(v2)<<"; v1 dot normal_vec = "<<v1.dot(normal_vec)<<endl;cout<<"(these should also be zero)"<<endl;// we now have two orthogonal vectors, both perpendicular to our defined plane's normal// we'll use these to generate some points that lie in our defined plane:int npts= 10; // create this many planar pointsEigen::MatrixXd points_mat(3,npts); // create a matrix, double-precision values, 3 rows and npts columns// we will populate this with 3-D points, column by columnEigen::Vector3d point; //a 3x1 vectorEigen::Vector2d rand_vec; //a 2x1 vector//generate random points that all lie on plane defined by distance and normal_vecfor (int ipt = 0;ipt<npts;ipt++) {// MatrixXd::Random returns uniform random numbers in the range (-1, 1).rand_vec.setRandom(2,1); // populate 2x1 vector with random values//cout<<"rand_vec: "<<rand_vec.transpose()<<endl; //optionally, look at these random values//construct a random point ON the plane normal to normal_vec at distance "dist" from origin:// a point on the plane is a*x_vec + b*y_vec + c*z_vec, where we may choose// x_vec = v1, y_vec = v2 (both of which are parallel to our plane) and z_vec is the plane normal// choose coefficients a and b to be random numbers, but "c" must be the plane's distance from the origin, "dist"point = rand_vec(0)*v1 + rand_vec(1)*v2 + dist*normal_vec;//save this point as the i'th column in the matrix "points_mat"points_mat.col(ipt) = point;}//all of the above points are identically on the plane defined by normal_vec and distcout<<"random points on plane (in columns): "<<endl; // display these points; only practical for relatively small number of pointscout<<points_mat<<endl;// add random noise to these points in range [-0.1,0.1]Eigen::MatrixXd Noise = Eigen::MatrixXd::Random(3,npts);cout<<"noise_gain = "<<g_noise_gain<<"; edit this as desired"<<endl;// add two matrices, term by term. Also, scale all points in a matrix by a scalar: Noise*g_noise_gainpoints_mat = points_mat + Noise*g_noise_gain; cout<<"random points on plane (in columns) w/ noise: "<<endl;cout<<points_mat<<endl;//xxxxxxxxxxxxxxxxxx DONE CREATING PLANAR DATA xxxxxxxxxxxxxxxxxx// xxxxxxxxxxxxxxx NOW, INTERPRET THE DATA TO DISCOVER THE UNDERLYING PLANE xxxxxxxx//now let's see if we can discover the plane from the data:cout<<endl<<endl;ROS_INFO("starting identification of plane from data: ");// first compute the centroid of the data:// here's a handy way to initialize data to all zeros; more variants exist// see http://eigen.tuxfamily.org/dox/AsciiQuickReference.txtEigen::Vector3d centroid = Eigen::MatrixXd::Zero(3,1);//add all the points together:npts = points_mat.cols(); // number of points = number of columns in matrix; check the sizecout<<"matrix has ncols = "<<npts<<endl;for (int ipt =0;ipt<npts;ipt++) {centroid+= points_mat.col(ipt); //add all the column vectors together}centroid/=npts; //divide by the number of points to get the centroidcout<<"centroid: "<<centroid.transpose()<<endl;// subtract this centroid from all points in points_mat:Eigen::MatrixXd points_offset_mat = points_mat;for (int ipt =0;ipt<npts;ipt++) {points_offset_mat.col(ipt) = points_offset_mat.col(ipt)-centroid;}//compute the covariance matrix w/rt x,y,z:Eigen::Matrix3d CoVar;CoVar = points_offset_mat*(points_offset_mat.transpose()); //3xN matrix times Nx3 matrix is 3x3cout<<"covariance: "<<endl;cout<<CoVar<<endl;// here is a more complex object: a solver for eigenvalues/eigenvectors;// we will initialize it with our covariance matrix, which will induce computing eval/evec pairsEigen::EigenSolver<Eigen::Matrix3d> es3d(CoVar);Eigen::VectorXd evals; //we'll extract the eigenvalues to here//cout<<"size of evals: "<<es3d.eigenvalues().size()<<endl;//cout<<"rows,cols = "<<es3d.eigenvalues().rows()<<", "<<es3d.eigenvalues().cols()<<endl;cout << "The eigenvalues of CoVar are:" << endl << es3d.eigenvalues().transpose() << endl;cout<<"(these should be real numbers, and one of them should be zero)"<<endl;cout << "The matrix of eigenvectors, V, is:" << endl;cout<< es3d.eigenvectors() << endl << endl;cout<< "(these should be real-valued vectors)"<<endl;// in general, the eigenvalues/eigenvectors can be complex numbers//however, since our matrix is self-adjoint (symmetric, positive semi-definite), we expect// real-valued evals/evecs; we'll need to strip off the real parts of the solutionevals= es3d.eigenvalues().real(); // grab just the real partscout<<"real parts of evals: "<<evals.transpose()<<endl;// our solution should correspond to an e-val of zero, which will be the minimum eval// (all other evals for the covariance matrix will be >0)// however, the solution does not order the evals, so we'll have to find the one of interest ourselvesdouble min_lambda = evals[0]; //initialize the hunt for min evalEigen::Vector3cd complex_vec; // here is a 3x1 vector of double-precision, complex numbersEigen::Vector3d est_plane_normal;complex_vec=es3d.eigenvectors().col(0); // here's the first e-vec, corresponding to first e-val//cout<<"complex_vec: "<<endl;//cout<<complex_vec<<endl;est_plane_normal = complex_vec.real(); //strip off the real part//cout<<"real part: "<<est_plane_normal.transpose()<<endl;//est_plane_normal = es3d.eigenvectors().col(0).real(); // evecs in columnsdouble lambda_test;int i_normal=0;//loop through "all" ("both", in this 3-D case) the rest of the solns, seeking min e-valfor (int ivec=1;ivec<3;ivec++) {lambda_test = evals[ivec];if (lambda_test<min_lambda) {min_lambda =lambda_test;i_normal= ivec; //this index is closer to index of min evalest_plane_normal = es3d.eigenvectors().col(ivec).real();}}// at this point, we have the minimum eval in "min_lambda", and the plane normal// (corresponding evec) in "est_plane_normal"/// these correspond to the ith entry of i_normalcout<<"min eval is "<<min_lambda<<", corresponding to component "<<i_normal<<endl;cout<<"corresponding evec (est plane normal): "<<est_plane_normal.transpose()<<endl;cout<<"correct answer is: "<<normal_vec.transpose()<<endl;double est_dist = est_plane_normal.dot(centroid);cout<<"est plane distance from origin = "<<est_dist<<endl;cout<<"correct answer is: "<<dist<<endl;cout<<endl<<endl;//xxxx one_vec*dist = point.dot(nx,ny,nz)// so, one_vec = points_mat.transpose()*x_vec, where x_vec = [nx;ny;nz]/dist (does not work if dist=0)// this is of the form: b = A*x, an overdetermined system of eqns// solve this using one of many Eigen methods// see: http://eigen.tuxfamily.org/dox/group__TutorialLinearAlgebra.htmlROS_INFO("2ND APPROACH b = A*x SOLN");Eigen::VectorXd ones_vec= Eigen::MatrixXd::Ones(npts,1); // this is our "b" vector in b = A*xEigen::MatrixXd A = points_mat.transpose(); // make this a Nx3 matrix, where points are along the rows// we'll pick the "full pivot LU" solution approach; see: http://eigen.tuxfamily.org/dox/group__TutorialLinearAlgebra.html// a matrix in "Eigen" has member functions that include solution methods to this common problem, b = A*x// use: x = A.solution_method(b)Eigen::Vector3d x_soln = A.fullPivLu().solve(ones_vec);//cout<<"x_soln: "<<x_soln.transpose()<<endl;double dist_est2 = 1.0/x_soln.norm();x_soln*=dist_est2;cout<<"normal vec, 2nd approach: "<<x_soln.transpose()<<endl;cout<<"plane distance = "<<dist_est2<<endl;return 0;// while (ros::ok()) {// sleep_timer.sleep();// } }

    運(yùn)行結(jié)果:

    總結(jié)

    以上是生活随笔為你收集整理的ROS中使用Eigen库[不定期更新]的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。