Orocos KDL的安装与使用
1. 安装
1.1 克隆KDL的仓库
1 git clone https://github.com/orocos/orocos_kinematics_dynamics.git
BASH
1.2 编译以及安装
进入orocos_kinematics_dynamics下的orocos_kdl文件夹,创建build文件夹,然后进入build文件夹:
1 2 3 cd orocos_kinematics_dynamics/orocos_kdlmkdir buildcd build
BASH
使用cmake编译:
安装:
这里的安装路径是默认的/usr/local/include。
1.3 配置CMakeLists.txt
在CMakeLists.txt中添加以下内容:
1 2 find_package (orocos_kdl REQUIRED)include_directories (${orocos_kdl_INCLUDE_DIRS} )
CMAKE
在target_link_libraries()中添加${orocos_kdl_LIBRARIES}
1 2 3 4 target_link_libraries (${PROJECT_NAME} ${catkin_LIBRARIES} ${orocos_kdl_LIBRARIES} )
CMAKE
有的博客中链接的是orocos-kdl
orocos-kdl-models,这里visp_ros仿真环境中使用的是${orocos_kdl_LIBRARIES}。
2. 使用
2.1 引用头文件
1 2 3 4 5 6 7 8 9 10 11 #include <kdl/chain.hpp> #include <kdl/chainfksolver.hpp> #include <kdl/chainfksolverpos_recursive.hpp> #include <kdl/chainiksolverpos_nr.hpp> #include <kdl/chainiksolverpos_nr_jl.hpp> #include <kdl/chainiksolvervel_pinv.hpp> #include <kdl/chainjnttojacsolver.hpp> #include <kdl/chainidsolver_recursive_newton_euler.hpp> #include <kdl/chaindynparam.hpp> #include <kdl/frames_io.hpp> #include <kdl/solveri.hpp>
CPP
2.2 创建机器人模型
初始化KDL的chain需要机械臂的DH参数,这里以franka机械臂为例,其DH参数可以在官方文档 中找到。
我们首先定义好相关变量:
1 2 3 4 KDL::Chain chain_; KDL::ChainFkSolverPos_recursive* fksolver_; KDL::ChainJntToJacSolver* jacobian_solver_; KDL::ChainDynParam* dyn_param_solver_;
CPP
通过franka机械臂的DH参数初始化机械臂的KDL模型,调用addSegment()函数添加每个关节的DH参数。(这里是从visp_ros中的vpRobotFrankaSim类中获取的DH参数,实际使用时可能需要根据自己的机械臂进行修改)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 chain_.addSegment ( KDL::Segment ( KDL::Joint ( KDL::Joint::None ), KDL::Frame::DH_Craig1989 ( 0.0 , 0.0 , 0.333 , 0.0 ) ) ); chain_.addSegment ( KDL::Segment ( KDL::Joint ( KDL::Joint::RotZ ), KDL::Frame::DH_Craig1989 ( 0.0 , -M_PI_2, 0.0 , 0.0 ) ) ); chain_.addSegment ( KDL::Segment ( KDL::Joint ( KDL::Joint::RotZ ), KDL::Frame::DH_Craig1989 ( 0.0 , M_PI_2, 0.316 , 0.0 ) ) ); chain_.addSegment ( KDL::Segment ( KDL::Joint ( KDL::Joint::RotZ ), KDL::Frame::DH_Craig1989 ( 0.0825 , M_PI_2, 0.0 , 0.0 ) ) ); chain_.addSegment ( KDL::Segment ( KDL::Joint ( KDL::Joint::RotZ ), KDL::Frame::DH_Craig1989 ( -0.0825 , -M_PI_2, 0.384 , 0.0 ) ) ); chain_.addSegment ( KDL::Segment ( KDL::Joint ( KDL::Joint::RotZ ), KDL::Frame::DH_Craig1989 ( 0.0 , M_PI_2, 0.0 , 0.0 ) ) ); chain_.addSegment ( KDL::Segment ( KDL::Joint ( KDL::Joint::RotZ ), KDL::Frame::DH_Craig1989 ( 0.088 , M_PI_2, 0.0 , 0.0 ) ) ); chain_.addSegment ( KDL::Segment ( KDL::Joint ( KDL::Joint::RotZ ), KDL::Frame::DH_Craig1989 ( 0.0 , 0.0 , 0.107 , 0.0 ) ) );
CPP
初始化机械臂的正运动学求解器、雅克比矩阵求解器和动力学参数求解器:
1 2 3 fksolver_ = new KDL::ChainFkSolverPos_recursive ( chain_ ); jacobian_solver_ = new KDL::ChainJntToJacSolver ( chain_ ); dyn_param_solver_ = new KDL::ChainDynParam ( chain_, KDL::Vector ( 0.0 , 0.0 , -9.81 ) );
CPP
2.3 正运动学求解
通过机械臂的正运动学求解器求解机械臂的末端位姿:
1 2 3 KDL::JntArray q (7 ) ; KDL::Frame p_out; fksolver_->JntToCart ( q, p_out );
CPP
这里的q是机械臂的关节角度,p_out是机械臂的末端位姿。使用时需要将机械臂的关节角度赋值给q,然后调用fksolver_->JntToCart(
q, p_out )即可得到机械臂的末端位姿。
p_out是一个4x4的矩阵,可以通过p_out.M和p_out.p分别获取旋转矩阵和平移向量。而机械臂的关节角度q一般可以通过机械臂的驱动器获取。
2.4 雅克比矩阵求解
通过机械臂的雅克比矩阵求解器求解机械臂的雅克比矩阵:
1 2 3 KDL::JntArray q (7 ) ; KDL::Jacobian J; jacobian_solver_->JntToJac ( q, J );
CPP
可以看到,我们只需要得到机械臂的关节角度q,然后调用jacobian_solver_->JntToJac(
q, J
)即可得到机械臂的雅克比矩阵J,这里的J是一个6x7的矩阵,可以通过J.data获取雅克比矩阵的数据,或者直接访问J(i,j)获取雅克比矩阵的第i行第j列的元素。
JntToJac()函数的第一个参数是机械臂的关节角度,第二个参数是机械臂的雅克比矩阵,第三个参数segmentNR是要计算雅克比矩阵的末端关节的编号,默认为机械臂的末端关节(-1),如果需要计算其他关节的雅克比矩阵,可以指定segmentNR。官方给出的函数原型如下:
1 2 3 4 5 6 7 8 9 10 11 12 virtual int JntToJac (const JntArray& q_in, Jacobian& jac, int segmentNR=-1 ) ;
CPP
2.5 动力学参数求解
通过机械臂的动力学参数求解器求解机械臂的动力学参数:
1 2 3 4 5 6 KDL::JntArray q (7 ) ; KDL::JntArray q_dot (7 ) ; KDL::JntArray coriolis (7 ) ; KDL::JntSpaceInertiaMatrix mass (7 ) ; dyn_param_solver_->JntToCoriolis ( q, q_dot, coriolis ); dyn_param_solver_->JntToMass ( q, mass );
CPP
计算机械臂的动力学参数时,需要机械臂的关节角度q和关节速度q_dot,然后调用dyn_param_solver_->JntToCoriolis(
q, q_dot, coriolis
)即可得到机械臂的科里奥利力矩coriolis,调用dyn_param_solver_->JntToMass(
q, mass
)即可得到机械臂的惯性力矩mass。这里的coriolis和mass都是7维的向量,可以通过coriolis.data和mass.data获取数据,或者直接访问coriolis(i)和mass(i)获取第i个关节的科里奥利力矩和惯性力矩。
在仿真环境中测试时,发现通过这样的方式求解的科里奥利力矩和惯性力矩是空的,暂时还不清楚原因。
函数原型如下:
1 2 3 virtual int JntToCoriolis (const JntArray &q, const JntArray &q_dot, JntArray &coriolis) ;virtual int JntToMass (const JntArray &q, JntSpaceInertiaMatrix& H) ;virtual int JntToGravity (const JntArray &q,JntArray &gravity) ;
CPP
最后不要忘记释放内存:
1 2 3 delete fksolver_;delete jacobian_solver_;delete dyn_param_solver_;
CPP
3. 参考资料