kinton_arm_task_priority_control_alg_node.cpp
Go to the documentation of this file.
00001 #include "kinton_arm_task_priority_control_alg_node.h"
00002 
00003 using namespace KDL;
00004 using namespace Eigen;
00005 using namespace std;
00006 
00007 KintonArmTaskPriorityControlAlgNode::KintonArmTaskPriorityControlAlgNode(void) :
00008   algorithm_base::IriBaseAlgorithm<KintonArmTaskPriorityControlAlgorithm>()
00009 {
00010   //init class attributes if necessary
00011   this->loop_rate_ = 100;//in [Hz]
00012 
00013   this->init_ = true;
00014   //init_arm();
00015 
00016   this->time_ = ros::Time::now();
00017 
00018   this->cam_vel_ = MatrixXd::Zero(6,1);
00019   this->v_rollpitch_ = MatrixXd::Zero(2,1);
00020 
00021   this->num_joints_ = 0;
00022   this->cam_vel_ok_ = false;
00023   this->v_rollpitch_ = MatrixXd::Zero(2,1);
00024   this->q_rollpitch_ = MatrixXd::Zero(2,1);
00025   this->gain_sec_task_ = MatrixXd::Zero(3,1);
00026 
00027   this->public_node_handle_.param<bool>("arm_unina", this->arm_unina_, "true" );
00028   this->public_node_handle_.param<bool>("arm_catec", this->arm_catec_, "false" );
00029   this->public_node_handle_.param<bool>("enable_sec_task", this->enable_sec_task_, "true" );
00030 
00031   ros::NodeHandle nh;
00032  
00033   string tip_name, root_name, optical_name;
00034   string xml_string;
00035   Tree tree;   
00036   string urdf_xml,full_urdf_xml;
00037   nh.param("urdf_xml",urdf_xml,string("robot_description"));
00038   nh.searchParam(urdf_xml,full_urdf_xml);      
00039   ROS_DEBUG("Reading xml file from parameter server\n");
00040   if (!nh.getParam(full_urdf_xml, xml_string)){
00041     ROS_ERROR("Could not load the xml from parameter server: %s\n", urdf_xml.c_str());
00042   }
00043   if (!nh.getParam("root_name", root_name)){
00044     ROS_ERROR("No root name found on parameter server");
00045   }
00046   if (!nh.getParam("tip_name", tip_name)){
00047     ROS_ERROR("No tip name found on parameter server");
00048   }
00049 
00050   // KDL Parser to create a KDL chain
00051   if (!kdl_parser::treeFromString(xml_string, tree)){
00052     ROS_ERROR("Could not initialize tree object");
00053   }
00054   if (!tree.getChain(root_name, tip_name, this->kdl_chain_)){
00055     ROS_ERROR("Could not initialize kdl_chain object");
00056   }
00057 
00058   // Get Joints Information
00059   urdf::Model robot_model;
00060   if (!robot_model.initString(xml_string)) {
00061     ROS_ERROR("Could not initialize robot model");
00062   }
00063   if (!readJoints(robot_model,root_name,tip_name)) {
00064     ROS_ERROR("Could not read information about the joints");
00065   }
00066 
00067   if (!nh.getParam("optical_frame_id", optical_name)){
00068     ROS_ERROR("No camera optical frame name found on parameter server");
00069   }
00070 
00071   // Get Homogenous transform
00072   this->Tcam_in_tip_ = get_HT_cam_in_tip(optical_name,tip_name);
00073 
00074   // [init publishers]
00075   this->joints_pub_publisher_ = this->public_node_handle_.advertise<sensor_msgs::JointState>("arm_joints_states", 10);
00076   this->quad_vel_publisher_ = this->public_node_handle_.advertise<geometry_msgs::Twist>("cmd_vel", 10);
00077   
00078   // [init subscribers]
00079   this->cam_vel_subscriber_ = this->public_node_handle_.subscribe("cam_vel", 100, &KintonArmTaskPriorityControlAlgNode::cam_vel_callback, this);
00080   this->odom_subscriber_ = this->public_node_handle_.subscribe("odom", 100, &KintonArmTaskPriorityControlAlgNode::odom_callback, this);
00081   this->input_tag_subscriber_ = this->public_node_handle_.subscribe("input_tag", 10, &KintonArmTaskPriorityControlAlgNode::input_tag_callback, this);
00082 
00083   // [init services]
00084   
00085   // [init clients]
00086   
00087   // [init action servers]
00088   
00089   // [init action clients]
00090 }
00091 
00092 KintonArmTaskPriorityControlAlgNode::~KintonArmTaskPriorityControlAlgNode(void)
00093 {
00094   // [free dynamic memory]
00095 }
00096 
00097 void KintonArmTaskPriorityControlAlgNode::mainNodeThread(void)
00098 {
00099   
00100   // Initialize arm and time
00101   if (this->init_)
00102   {
00103     this->time_last_=this->time_;
00104     init_arm();
00105     // Initialize cmd_vel output
00106     this->vel_ = MatrixXd::Zero(6+this->num_joints_,1); 
00107     this->init_=false;
00108   }
00109 
00110   this->dt_=(this->time_-this->time_last_).toSec(); 
00111 
00112 
00113   if (this->cam_vel_ok_ && this->activate_){
00114 
00115     this->alg_.lock();          
00116     this->task_priority_ctrl_.task_priority_ctrl(this->cam_vel_,this->arm_unina_,
00117                                                  this->arm_catec_,this->enable_sec_task_,
00118                                                  this->Tcam_in_tip_,this->Ttag_in_cam_,
00119                                                  this->lambda_robot_,this->gain_sec_task_,
00120                                                  this->q_rollpitch_,this->v_rollpitch_,
00121                                                  this->kdl_chain_,this->joint_info_,this->dt_,this->q_,this->vel_);
00122     this->alg_.unlock();   
00123   }
00124   else 
00125   {
00126     this->init_ = true; 
00127   }
00128 
00129   // [fill msg structures]
00130 
00131   // fill arm joints message
00132   for (int jj=0; jj<this->num_joints_; ++jj){
00133     this->JointState_msg_.position[jj]=this->q_(6+jj,0);
00134     this->JointState_msg_.velocity[jj]=this->vel_(6+jj);
00135     this->JointState_msg_.effort[jj]=1;
00136   }    
00137 
00138   // fill quadrotor velocity msg 
00139   this->Twist_msg_.linear.x = this->vel_(0,0);
00140   this->Twist_msg_.linear.y = this->vel_(1,0);
00141   this->Twist_msg_.linear.z = this->vel_(2,0); 
00142   this->Twist_msg_.angular.x = this->vel_(3,0);  
00143   this->Twist_msg_.angular.y = this->vel_(4,0);  
00144   this->Twist_msg_.angular.z = this->vel_(5,0); 
00145 
00146   // adding an offset to the thrust to compensate the arm weight
00147   if (this->arm_unina_){
00148     this->Twist_msg_.linear.z= this->Twist_msg_.linear.z + 0.15;
00149   }
00150   else if (this->arm_catec_){
00151     this->Twist_msg_.linear.z= this->Twist_msg_.linear.z + 0;
00152   }
00153   
00154   // [fill srv structure and make request to the server]
00155   
00156   // [fill action structure and make request to the action server]
00157 
00158   // [publish messages]
00159   this->quad_vel_publisher_.publish(this->Twist_msg_);
00160   this->joints_pub_publisher_.publish(this->JointState_msg_); 
00161 }
00162 
00163 /*  [subscriber callbacks] */
00164 void KintonArmTaskPriorityControlAlgNode::cam_vel_callback(const geometry_msgs::TwistWithCovariance::ConstPtr& msg) 
00165 { 
00166   //ROS_INFO("KintonArmTaskPriorityControlAlgNode::twist_cov_callback: New Message Received"); 
00167 
00168   //use appropiate mutex to shared variables if necessary 
00169   this->cam_vel_mutex_.enter(); 
00170 
00171   if (msg->covariance[0]<1000 && this->activate_)
00172   {
00173     this->cam_vel_(0,0) = msg->twist.linear.x;
00174     this->cam_vel_(1,0) = msg->twist.linear.y;
00175     this->cam_vel_(2,0) = msg->twist.linear.z;
00176     this->cam_vel_(3,0) = msg->twist.angular.x;
00177     this->cam_vel_(4,0) = msg->twist.angular.y;
00178     this->cam_vel_(5,0) = msg->twist.angular.z;
00179 
00180     this->cam_vel_ok_ = true;
00181   }
00182   else
00183   {
00184     this->cam_vel_ = MatrixXd::Zero(6,1);
00185     this->cam_vel_ok_ = false;
00186   } 
00187 
00188   //unlock previously blocked shared variables 
00189   this->cam_vel_mutex_.exit(); 
00190 }
00191 
00192 void KintonArmTaskPriorityControlAlgNode::odom_callback(const nav_msgs::Odometry::ConstPtr& msg) 
00193 { 
00194   //ROS_INFO("KintonVsControlAlgNode::odom_callback: New Message Received"); 
00195 
00196   //use appropiate mutex to shared variables if necessary 
00197   this->odom_mutex_.enter(); 
00198 
00199   // In the case of a underactuation
00200   // Extract the Non controllable DOF velocities
00201   this->v_rollpitch_ = MatrixXd::Zero(2,1);
00202   this->q_rollpitch_ = MatrixXd::Zero(2,1);
00203 
00204   if (msg->twist.covariance[0]<100)
00205   {
00206 
00207     if (!isnan(msg->twist.twist.angular.x) && !isnan(msg->twist.twist.angular.y)){
00208       this->v_rollpitch_(0,0) = msg->twist.twist.angular.x;
00209       this->v_rollpitch_(1,0) = msg->twist.twist.angular.y; 
00210     }
00211 
00212     if (!isnan(msg->pose.pose.orientation.x)){
00213 
00214       // Convert quaternion to RPY.
00215       tf::Quaternion qt;
00216       double quad_roll, quad_pitch, quad_yaw;
00217       tf::quaternionMsgToTF(msg->pose.pose.orientation, qt);
00218       tf::Matrix3x3(qt).getRPY(quad_roll, quad_pitch, quad_yaw);
00219 
00220       this->q_rollpitch_(0,0) = quad_roll;
00221       this->q_rollpitch_(1,0) = quad_pitch; 
00222     }
00223 
00224   }   
00225 
00226   this->v_rollpitch_ = MatrixXd::Zero(2,1);
00227 
00228   //unlock previously blocked shared variables 
00229   this->odom_mutex_.exit(); 
00230 }
00231 
00232 void KintonArmTaskPriorityControlAlgNode::input_tag_callback(const ar_pose::ARMarkers::ConstPtr& msg) 
00233 { 
00234   this->input_tag_mutex_.enter();
00235 
00236   this->time_last_ = this->time_;
00237   
00238   
00239   if (msg->markers.empty()){
00240     this->Ttag_in_cam_ = Matrix4d::Zero();
00241     this->Ttag_in_cam_.block(0,0,3,3) = Matrix3d::Identity();
00242     this->Ttag_in_cam_(3,3) = 1.0;
00243     this->time_ = ros::Time::now();
00244     this->init_ = true;
00245     ROS_INFO("No tag detected");
00246   }
00247 
00248   if ((!msg->markers.empty()) && ((!std::isnan(msg->markers[0].pose.pose.orientation.x) && std::isfinite(msg->markers[0].pose.pose.orientation.x)) || (!std::isnan(msg->markers[1].pose.pose.orientation.x) && std::isfinite(msg->markers[1].pose.pose.orientation.x)))){
00249         
00250     this->time_ = msg->markers.back().header.stamp;
00251     this->pose_ = msg->markers.back().pose.pose;
00252     // Convert pose from marker (quaternion to RPY).
00253     tf::Transform tf_pose;
00254     
00255     double x,y,z,yaw,pitch,roll;
00256     tf::poseMsgToTF(this->pose_, tf_pose);
00257     tf_pose.getBasis().getRPY(roll,pitch,yaw);
00258     
00259     Matrix3d Rot;
00260     // euler convention zyx  
00261     Rot = AngleAxisd(yaw, Vector3d::UnitZ()) \
00262       * AngleAxisd(pitch, Vector3d::UnitY()) \
00263       * AngleAxisd(roll, Vector3d::UnitX());
00264     
00265     x = this->pose_.position.x;
00266     y = this->pose_.position.y;
00267     z = this->pose_.position.z;
00268     
00269     this->Ttag_in_cam_=Matrix4d::Zero();
00270     if (!std::isnan(Rot(0,0)))  this->Ttag_in_cam_.block(0,0,3,3)=Rot;
00271      
00272     this->Ttag_in_cam_.block(0,3,3,1) << x, y, z;
00273     this->Ttag_in_cam_.row(3) << 0, 0, 0, 1;
00274   }  
00275   //unlock previously blocked shared variables 
00276   this->input_tag_mutex_.exit();
00277 }
00278 
00279 /*  [service callbacks] */
00280 
00281 /*  [action callbacks] */
00282 
00283 /*  [action requests] */
00284 
00285 Matrix4d KintonArmTaskPriorityControlAlgNode::getTransform(const string& frame1, const string& frame2)
00286 {
00287 //Get fixed transforms between the IMU data and the robot frame
00288   tf::TransformListener listener;
00289   tf::StampedTransform transform;
00290 
00291   try {
00292     //listener.waitForTransform(frame1,frame2, ros::Time(0));
00293     listener.lookupTransform(frame1,frame2, ros::Time(0), transform);
00294   } 
00295   catch (tf::TransformException ex) {
00296     //ROS_ERROR("End-effector in Inertial frame Transform error: %s",ex.what());
00297   }
00298 
00299   double roll,pitch,yaw;
00300   tf::Quaternion q =  transform.getRotation();
00301   tf::Matrix3x3(q).getRPY(roll,pitch,yaw); 
00302 
00303   Matrix3d Rot;
00304   Rot = AngleAxisd(yaw, Vector3d::UnitZ()) \
00305       * AngleAxisd(pitch, Vector3d::UnitY()) \
00306       * AngleAxisd(roll, Vector3d::UnitX());
00307   Matrix4d T = Matrix4d::Zero();
00308 
00309   T.block(0,0,3,3) = Rot;
00310   T(0,3) = transform.getOrigin().x();
00311   T(1,3) = transform.getOrigin().y();
00312   T(2,3) = transform.getOrigin().z();
00313   T(3,3) = 1.0;  
00314 
00315   //ROS_INFO("x: %f y: %f z: %f roll: %f, pitch: %f, yaw: %f",transform.getOrigin().x(),transform.getOrigin().y(),transform.getOrigin().z(),roll,pitch,yaw);
00316   return T;
00317 }
00318 
00319 void KintonArmTaskPriorityControlAlgNode::init_arm()
00320 {
00321 
00322   this->q_ = MatrixXd::Zero(6+this->num_joints_,1);
00323 
00324   //UNINA arm
00325   if (this->arm_unina_ && !this->arm_catec_){
00326 
00327     // frontal marker
00328     //this->q_ << 0, 0, 2.5, 0, 0, 0, 0, -0.5, 2, 3, 0;
00329     //BO this->q_ << 0, 0, 2.5, 0, 0, 0, 0, 0.2, 1.7, 2, 0;
00330     //this->q_ << 0, 0, 2.5, 0, 0, 0, 0, 0.2, 1.7, 2, 0;
00331     //this->q_ << 0, 0, 2.5, 0, 0, 0, 0, 1.5, 0, 2, 0;
00332     //this->q_ << 0, 0, 2.5, 0, 0, 0, 0, -0.5, 1.7, 1, 0;
00333     // extended
00334     this->q_ << 0, 0, 2.5, 0, 0, 0, 0, 0, 3.1415, 3.1415, 0;
00335   }
00336   //CATEC arm
00337   else if (this->arm_catec_ && !this->arm_unina_){
00338      
00339     // this->q_ << 0, 0, 2.5, 0, 0, 0, 0, 3.14159/2, 0, 0, 0, 0;
00340     this->q_ << 0, 0, 2.5, 0, 0, 0, 0, 2, -2, 0, 1.5707, 0;
00341   }
00342   else if ((this->arm_unina_ && this->arm_catec_) || (!this->arm_unina_ && !this->arm_catec_)){
00343       ROS_ERROR("Wrong arms configuration");
00344   }
00345 
00346   this->JointState_msg_.header.stamp=ros::Time::now();
00347   this->JointState_msg_.header.frame_id="";
00348   this->JointState_msg_.name.resize(this->num_joints_);
00349   this->JointState_msg_.position.resize(this->num_joints_);
00350   this->JointState_msg_.velocity.resize(this->num_joints_);
00351   this->JointState_msg_.effort.resize(this->num_joints_);
00352   for (int ii = 0; ii < this->num_joints_; ++ii)
00353   {
00354     string quad_str="quadrotor::";
00355     stringstream joint_name;
00356     joint_name << quad_str << this->joint_info_.at(ii).link_child;
00357     this->JointState_msg_.name[ii]=joint_name.str();
00358   }
00359 }
00360 
00361 void KintonArmTaskPriorityControlAlgNode::node_config_update(Config &config, uint32_t level)
00362 {
00363   this->alg_.lock();
00364   this->activate_=config.sim_activate;
00365   double lambda_quadrotor=config.lambda_quadrotor;
00366   double lambda_arm=config.lambda_arm;
00367   this->enable_sec_task_ = config.enable_sec_task;
00368   // this->gain_sec_task_(0,0) = config.gain_sec_task_stabil;
00369   this->gain_sec_task_(1,0) = config.gain_sec_task_CoG;
00370   this->gain_sec_task_(2,0) = config.gain_sec_task_jntlim;
00371 
00372   this->lambda_robot_ = MatrixXd::Zero(4+this->num_joints_,1);
00373 
00374   for (int i = 0; i < 4; ++i)
00375   {
00376     this->lambda_robot_(i,0)=lambda_quadrotor;
00377   }
00378   for (int i = 0; i < this->num_joints_; ++i)
00379   {
00380     this->lambda_robot_(4+i,0)=lambda_arm;
00381   }
00382 
00383   this->alg_.unlock();
00384 }
00385 
00386 void KintonArmTaskPriorityControlAlgNode::addNodeDiagnostics(void)
00387 {
00388 }
00389 
00390 /* main function */
00391 int main(int argc,char *argv[])
00392 {
00393   return algorithm_base::main<KintonArmTaskPriorityControlAlgNode>(argc, argv, "kinton_arm_task_priority_control_alg_node");
00394 }
00395 
00396 bool KintonArmTaskPriorityControlAlgNode::readJoints(urdf::Model &robot_model,const string& root_name,const string& tip_name) {
00397   
00398   int num_joints = 0;
00399   // get joint maxs and mins
00400   boost::shared_ptr<const urdf::Link> link = robot_model.getLink(tip_name);
00401   boost::shared_ptr<const urdf::Joint> joint;
00402 
00403   while (link && link->name != root_name) {
00404     joint = robot_model.getJoint(link->parent_joint->name);
00405     if (!joint) {
00406       ROS_ERROR("Could not find joint: %s",link->parent_joint->name.c_str());
00407       return false;
00408     }
00409     if (joint->type != urdf::Joint::UNKNOWN && joint->type != urdf::Joint::FIXED) {
00410       //ROS_INFO( "adding joint: [%s]", joint->name.c_str() );
00411       num_joints++;
00412     }
00413     link = robot_model.getLink(link->getParent()->name);
00414   }
00415 
00416   this->num_joints_=num_joints;
00417   this->joint_info_.resize(num_joints);
00418   
00419   link = robot_model.getLink(tip_name);
00420   int ii = 0;
00421   while (link && ii < num_joints) {
00422     joint = robot_model.getJoint(link->parent_joint->name);
00423     if (joint->type != urdf::Joint::UNKNOWN && joint->type != urdf::Joint::FIXED) {
00424       //ROS_INFO( "getting bounds for joint: [%s]", joint->name.c_str() );
00425 
00426       float lower, upper;
00427       if ( joint->type != urdf::Joint::CONTINUOUS ) {
00428         lower = joint->limits->lower;
00429         upper = joint->limits->upper;
00430       } else {
00431         lower = -M_PI;
00432         upper = M_PI;
00433       }
00434       int index = num_joints - ii -1;
00435       this->joint_info_.at(index).joint_min = lower;
00436       this->joint_info_.at(index).joint_max = upper;
00437       this->joint_info_.at(index).link_child = link->name;
00438       this->joint_info_.at(index).link_parent = link->getParent()->name;
00439       ii++;
00440     }
00441     link = robot_model.getLink(link->getParent()->name);
00442   }
00443   return true;
00444 }
00445 
00446 Matrix4d KintonArmTaskPriorityControlAlgNode::get_HT_cam_in_tip(const string& cam_frame, const string& tip_frame)
00447 {
00448   Matrix4d Tcam_in_tip = Matrix4d::Zero();
00449 
00450   tf::TransformListener listener;
00451   tf::StampedTransform transform;
00452   try{ 
00453       listener.waitForTransform(tip_frame, cam_frame, ros::Time(0), ros::Duration(1.0));
00454       listener.lookupTransform(tip_frame, cam_frame, ros::Time(0), transform);
00455       }
00456       catch (tf::TransformException ex){
00457         ROS_ERROR("%s",ex.what());
00458       }
00459   
00460   double x,y,z,roll,pitch,yaw;
00461   transform.getBasis().getRPY(roll, pitch, yaw);
00462   
00463   x=transform.getOrigin().x();
00464   y=transform.getOrigin().y();
00465   z=transform.getOrigin().z();
00466 
00467   Matrix3d Rot;
00468   // euler convention zyx    
00469   Rot = AngleAxisd(yaw, Vector3d::UnitZ()) \
00470        * AngleAxisd(pitch, Vector3d::UnitY()) \
00471      * AngleAxisd(roll, Vector3d::UnitX());
00472  
00473   Tcam_in_tip.block(0,0,3,3) = Rot;
00474   Tcam_in_tip(0,3) = x;
00475   Tcam_in_tip(1,3) = y;
00476   Tcam_in_tip(2,3) = z;
00477   Tcam_in_tip(3,3) = 1;
00478 
00479   return Tcam_in_tip;
00480 }


kinton_arm_task_priority_control
Author(s): Àngel Sanatamaria Navarro
autogenerated on Fri Dec 6 2013 21:37:38