visual_servo.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  *
00003  *  Copyright (c) 2012, Georgia Institute of Technology
00004  *  All rights reserved.
00005  *
00006  *  Redistribution and use in source and binary forms, with or without
00007  *  modification, are permitted provided that the following conditions
00008  *  are met:
00009  *
00010  *   * Redistributions of source code must retain the above copyright
00011  *     notice, this list of conditions and the following disclaimer.
00012  *   * Redistributions in binary form must reproduce the above
00013  *     copyright notice, this list of conditions and the following
00014  *     disclaimer in the documentation and/or other materials provided
00015  *     with the distribution.
00016  *   * Neither the name of the Georgia Institute of Technology nor the names of
00017  *     its contributors may be used to endorse or promote products derived
00018  *     from this software without specific prior written permission.
00019  *
00020  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00030  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031  *  POSSIBILITY OF SUCH DAMAGE.
00032  *********************************************************************/
00033 
00034 // ROS
00035 #include <ros/ros.h>
00036 #include <ros/package.h>
00037 
00038 #include <std_msgs/Header.h>
00039 #include <geometry_msgs/PointStamped.h>
00040 #include <geometry_msgs/PoseStamped.h>
00041 #include <geometry_msgs/TwistStamped.h>
00042 #include <geometry_msgs/Pose2D.h>
00043 #include <sensor_msgs/Image.h>
00044 #include <sensor_msgs/PointCloud2.h>
00045 #include <sensor_msgs/CameraInfo.h>
00046 #include <sensor_msgs/image_encodings.h>
00047 
00048 // TF
00049 #include <tf/transform_listener.h>
00050 #include <tf/transform_datatypes.h>
00051 
00052 // PCL
00053 #include <pcl/point_cloud.h>
00054 #include <pcl/point_types.h>
00055 #include <pcl_ros/transforms.h>
00056 
00057 // OpenCV
00058 #include <opencv2/core/core.hpp>
00059 #include <opencv2/imgproc/imgproc.hpp>
00060 #include <opencv2/highgui/highgui.hpp>
00061 
00062 // Boost
00063 #include <boost/shared_ptr.hpp>
00064 
00065 // STL
00066 #include <vector>
00067 #include <deque>
00068 #include <queue>
00069 #include <string>
00070 #include <sstream>
00071 #include <iostream>
00072 #include <fstream>
00073 #include <utility>
00074 #include <stdexcept>
00075 #include <float.h>
00076 #include <math.h>
00077 #include <time.h> // for srand(time(NULL))
00078 #include <cstdlib> // for MAX_RAND
00079 
00080 // Others
00081 #include <visual_servo/VisualServoTwist.h>
00082 
00083 #define DEBUG_MODE 0
00084 #define JACOBIAN_TYPE_INV 1
00085 #define JACOBIAN_TYPE_PSEUDO 2
00086 #define JACOBIAN_TYPE_AVG 3
00087 #define PBVS 0
00088 #define IBVS 1
00089 #define PI 3.14159265359
00090 
00091 typedef pcl::PointCloud<pcl::PointXYZ> XYZPointCloud;
00092 typedef struct {
00093   // pixels
00094   cv::Point image;
00095   // meters, note that xyz for this is different from the other one
00096   pcl::PointXYZ camera;
00097   // the 3d location in workspace frame
00098   pcl::PointXYZ workspace;
00099   pcl::PointXYZ workspace_angular;
00100 } VSXYZ;
00101 
00102 namespace VisualServoMsg
00103 {
00104   visual_servo::VisualServoPose createPoseMsg(float px, float py, float pz, float ox, float oy, float oz, float ow)
00105   {
00106     visual_servo::VisualServoPose p_srv;
00107     p_srv.request.p.header.stamp = ros::Time::now();
00108     p_srv.request.p.header.frame_id = "torso_lift_link";
00109     p_srv.request.p.pose.position.x = px;
00110     p_srv.request.p.pose.position.y = py;
00111     p_srv.request.p.pose.position.z = pz;
00112     p_srv.request.p.pose.orientation.x = ox;
00113     p_srv.request.p.pose.orientation.y = oy;
00114     p_srv.request.p.pose.orientation.z = oz;
00115     p_srv.request.p.pose.orientation.w = ow;
00116     return p_srv;
00117   }
00118 
00119   visual_servo::VisualServoTwist createTwistMsg(float err, double lx, double ly, double lz, double ax, double ay, double az)
00120   {
00121     visual_servo::VisualServoTwist msg;
00122     msg.request.error = err;
00123     msg.request.twist.header.stamp = ros::Time::now();
00124     msg.request.twist.header.frame_id = "torso_lift_link";
00125     msg.request.twist.twist.linear.x = lx;
00126     msg.request.twist.twist.linear.y = ly;
00127     msg.request.twist.twist.linear.z = lz;
00128     msg.request.twist.twist.angular.x = ax;
00129     msg.request.twist.twist.angular.y = ay;
00130     msg.request.twist.twist.angular.z = az;
00131     return msg;
00132   }
00133 
00134   visual_servo::VisualServoTwist createTwistMsg(cv::Mat velpos, cv::Mat velrot)
00135   {
00136     visual_servo::VisualServoTwist msg;
00137     msg.request.twist.twist.linear.x = velpos.at<float>(0,0);
00138     msg.request.twist.twist.linear.y = velpos.at<float>(1,0);
00139     msg.request.twist.twist.linear.z = velpos.at<float>(2,0);
00140     msg.request.twist.twist.angular.x = velrot.at<float>(0,0);
00141     msg.request.twist.twist.angular.y = velrot.at<float>(1,0);
00142     msg.request.twist.twist.angular.z = velrot.at<float>(2,0);
00143     return msg;
00144   }
00145   visual_servo::VisualServoTwist createTwistMsg(double lx, double ly, double lz, double ax, double ay, double az)
00146   {
00147     return createTwistMsg(0.0, lx, ly, lz, ax, ay, az);
00148   }
00149 
00150   visual_servo::VisualServoTwist createTwistMsg(float err, std::vector<double> in)
00151   {
00152     if (in.size() >= 6)
00153       return createTwistMsg(err, in.at(0), in.at(1), in.at(2),
00154         in.at(3), in.at(4), in.at(5)); 
00155    else
00156    {
00157     ROS_WARN("VisuaServoMsg >> Valid input needs 6 values. Returning 0");
00158     visual_servo::VisualServoTwist msg;
00159     return msg;
00160    }
00161   }
00162 
00163   visual_servo::VisualServoTwist createTwistMsg(float err, cv::Mat twist)
00164   {
00165   std::vector<double> vals; 
00166    for (int i = 0; i < twist.rows; i++)
00167    {
00168     for (int j = 0; j < twist.cols; j++)
00169     {
00170       vals.push_back((double) twist.at<float>(i,j));
00171     }
00172    }
00173    return createTwistMsg(err, vals);
00174   }
00175 }
00176 // using boost::shared_ptr;
00177 using geometry_msgs::TwistStamped;
00178 using geometry_msgs::PointStamped;
00179 using geometry_msgs::PoseStamped;
00180 using visual_servo::VisualServoTwist;
00181 using boost::shared_ptr;
00182 
00188 class VisualServo
00189 {
00190   public:
00191     VisualServo(int jacobian_type) :
00192       n_private_("~"), desired_jacobian_set_(false)
00193   {
00194     // user must specify the jacobian type
00195     jacobian_type_ = jacobian_type;
00196     std::string default_optical_frame = "/head_mount_kinect_rgb_optical_frame";
00197     n_private_.param("optical_frame", optical_frame_, default_optical_frame);
00198     std::string default_workspace_frame = "/torso_lift_link";
00199     n_private_.param("workspace_frame", workspace_frame_, default_workspace_frame);
00200 
00201     // others
00202     n_private_.param("gain_vel", gain_vel_, 1.0);
00203     n_private_.param("gain_rot", gain_rot_, 1.0);
00204     // n_private_.param("jacobian_type", jacobian_type_, JACOBIAN_TYPE_INV);
00205 
00206     try
00207     {
00208       ros::Time now = ros::Time(0);
00209       listener_.waitForTransform(workspace_frame_, optical_frame_,  now, ros::Duration(2.0));
00210     }
00211     catch (tf::TransformException e)
00212     {
00213       ROS_WARN_STREAM(e.what());
00214     }
00215   }
00216 
00217     void setCamInfo(sensor_msgs::CameraInfo cam_info)
00218     {
00219       cam_info_ = cam_info;
00220     }
00221 
00222     visual_servo::VisualServoTwist getTwist(std::vector<PoseStamped> goal, std::vector<PoseStamped> gripper)
00223     {
00224       // default to PBVS
00225       return getTwist(goal, gripper, PBVS);
00226     }
00227 
00228     visual_servo::VisualServoTwist getTwist(std::vector<PoseStamped> goal, std::vector<PoseStamped> gripper, int mode)
00229     {
00230       switch (mode)
00231       {
00232         case PBVS:
00233           return PBVSTwist(goal, gripper);
00234         default:
00235           return IBVSTwist(goal, gripper);
00236       }
00237     }
00238 
00239     visual_servo::VisualServoTwist getTwist(std::vector<VSXYZ> goal, std::vector<VSXYZ> gripper, cv::Mat error) 
00240     {
00241       return IBVSTwist(goal, gripper, error);
00242     }
00243 
00244     visual_servo::VisualServoTwist getTwist(std::vector<VSXYZ> goal, std::vector<VSXYZ> gripper)
00245     {
00246       return IBVSTwist(goal, gripper);
00247     }
00248 
00249     bool setDesiredInteractionMatrix(std::vector<VSXYZ> &pts) 
00250     {
00251       try 
00252       {
00253         cv::Mat im = getMeterInteractionMatrix(pts);
00254         if (countNonZero(im) > 0)
00255         {
00256           desired_jacobian_ = im;
00257           desired_jacobian_set_ = true;
00258           return true;
00259         }
00260       }
00261       catch(ros::Exception e)
00262       {
00263       }
00264       return false;
00265     }
00266 
00267     /**************************** 
00268      * Projection & Conversions
00269      ****************************/
00270     std::vector<VSXYZ> Point3DToVSXYZ(std::vector<pcl::PointXYZ> in, shared_ptr<tf::TransformListener> tf_)
00271     {
00272       std::vector<VSXYZ> ret;
00273       for (unsigned int i = 0; i < in.size(); i++)
00274       {
00275         ret.push_back(point3DToVSXYZ(in.at(i), tf_));
00276       }
00277       return ret;
00278     }
00279 
00280     VSXYZ point3DToVSXYZ(pcl::PointXYZ in, shared_ptr<tf::TransformListener> tf_)
00281     {
00282       // [X,Y,Z] -> [u,v] -> [x,y,z]
00283       VSXYZ ret;
00284 
00285       // 3D point in world frame
00286       pcl::PointXYZ in_c = in;
00287       cv::Point img = projectPointIntoImage(in_c, workspace_frame_, optical_frame_, tf_);
00288       cv::Mat temp = projectImagePointToPoint(img);
00289 
00290       float depth = sqrt(pow(in_c.z,2) + pow(temp.at<float>(0,0),2) + pow(temp.at<float>(1,0),2));
00291       pcl::PointXYZ _2d(temp.at<float>(0,0), temp.at<float>(1,0), depth);
00292       ret.image = img;
00293       // for simpler simulator, this will be the same
00294       ret.camera = _2d;
00295       ret.workspace= in;
00296       return ret;
00297     }
00298     PoseStamped VSXYZToPoseStamped(VSXYZ v)
00299     {
00300       PoseStamped p;
00301       p.pose.position.x = v.workspace.x;
00302       p.pose.position.y = v.workspace.y;
00303       p.pose.position.z = v.workspace.z;
00304       pcl::PointXYZ a = v.workspace_angular;
00305       p.pose.orientation = tf::createQuaternionMsgFromRollPitchYaw(a.x, a.y, a.z);
00306       return p;
00307     }
00308     std::vector<VSXYZ> CVPointToVSXYZ(XYZPointCloud cloud, cv::Mat depth_frame, std::vector<cv::Point> in) 
00309     {
00310       std::vector<VSXYZ> ret;
00311       for (unsigned int i = 0; i < in.size(); i++)
00312       {
00313         ret.push_back(CVPointToVSXYZ(cloud, depth_frame, in.at(i)));
00314       }
00315       return ret;
00316     }
00317 
00318     VSXYZ CVPointToVSXYZ(XYZPointCloud cloud, cv::Mat depth_frame, cv::Point in)
00319     {
00320       // [u,v] -> [x,y,z] (from camera intrinsics) & [X, Y, Z] (from PointCloud)
00321       VSXYZ ret;
00322       // pixel to meter value (using inverse of camera intrinsic) 
00323       cv::Mat temp = projectImagePointToPoint(in);
00324 
00325       // getZValue averages out z-value in a window to reduce noises
00326       pcl::PointXYZ _2d(temp.at<float>(0,0), temp.at<float>(1,0), getZValue(depth_frame, in.x, in.y));
00327       pcl::PointXYZ _3d = cloud.at(in.x, in.y);
00328 
00329       ret.image = in;
00330       ret.camera = _2d;
00331       ret.workspace= _3d;
00332       return ret;
00333     }
00334     cv::Point projectPointIntoImage(pcl::PointXYZ cur_point_pcl,
00335         std::string point_frame, std::string target_frame, shared_ptr<tf::TransformListener> tf_)
00336     {
00337       PointStamped cur_point;
00338       cur_point.header.frame_id = point_frame;
00339       cur_point.point.x = cur_point_pcl.x;
00340       cur_point.point.y = cur_point_pcl.y;
00341       cur_point.point.z = cur_point_pcl.z;
00342       return projectPointIntoImage(cur_point, target_frame, tf_);
00343     }
00344 
00345     void printVSXYZ(VSXYZ i)
00346     {
00347       printf("Im: %+.3d %+.3d\tCam: %+.3f %+.3f %+.3f\twork: %+.3f %+.3f %+.3f\n",\
00348           i.image.x, i.image.y, i.camera.x, i.camera.y, i.camera.z, i.workspace.x, i.workspace.y, i.workspace.z);
00349     }
00350 
00351   protected:
00352     ros::NodeHandle n_;
00353     ros::NodeHandle n_private_;
00354     // shared_ptr<tf::TransformListener> tf_;
00355     std::string workspace_frame_;
00356     std::string optical_frame_;
00357     tf::StampedTransform transform;
00358 
00359     tf::TransformListener listener_;
00360     // others
00361     int jacobian_type_;
00362     double gain_vel_;
00363     double gain_rot_;
00364     double term_threshold_;
00365     bool desired_jacobian_set_;
00366     cv::Mat desired_jacobian_;
00367     cv::Mat K;
00368     sensor_msgs::CameraInfo cam_info_;
00369 
00370     visual_servo::VisualServoTwist PBVSTwist(cv::Mat error_pose, cv::Mat error_rot)
00371     {
00372       cv::Mat velpos = -gain_vel_*error_pose;
00373       cv::Mat velrot = -gain_rot_*error_rot;
00374       return VisualServoMsg::createTwistMsg(velpos, velrot);
00375     }
00376 
00377     visual_servo::VisualServoTwist PBVSTwist(std::vector<PoseStamped> desired, std::vector<PoseStamped> pts)
00378     {
00379       // although PBVS takes in vector, we only need one pose from goal and gripper
00380       if (pts.size() != 1 || desired.size() != 1)
00381       {
00382         ROS_WARN("Visual Servo: Incorrect input to PBVS. Returning Zero Twist");
00383         return visual_servo::VisualServoTwist();
00384       }
00385 
00386       // TODO
00387       // need to transform from PoseStamped pose into torso 
00388       // for now, assume that the posestamped is already in torso
00389 
00390       // for all three features,
00391       geometry_msgs::Point cpos = pts.front().pose.position;
00392       geometry_msgs::Quaternion cquat = pts.front().pose.orientation;
00393       geometry_msgs::Point gpos = desired.front().pose.position;
00394       geometry_msgs::Quaternion gquat = desired.front().pose.orientation;
00395       // make cv::mat out of above values
00396       float tcpos[3] = {cpos.x, cpos.y, cpos.z};
00397       cv::Mat mcpos = cv::Mat(1, 3, CV_32F, tcpos).t();
00398 
00399       float tgpos[3] = {gpos.x, gpos.y, gpos.z};
00400       cv::Mat mgpos = cv::Mat(1, 3, CV_32F, tgpos).t();
00401 
00402       // need to convert quaternion into RPY and make cv::mat
00403       double tr, tp, ty;
00404       btQuaternion q1(gquat.x, gquat.y, gquat.z, gquat.w);
00405       btMatrix3x3(q1).getEulerYPR(ty, tp, tr);
00406       float tgquat[3] = {tr, tp, ty};
00407       // matrix-goal rotation
00408       cv::Mat mgrot = cv::Mat(1, 3, CV_32F, tgquat).t();
00409 
00410       btQuaternion q2(cquat.x, cquat.y, cquat.z, cquat.w);
00411       btMatrix3x3(q2).getEulerYPR(ty, tp, tr);
00412       float tcquat[3] = {tr, tp, ty};
00413       // matrix-current rotation
00414       cv::Mat mcrot = cv::Mat(1, 3, CV_32F, tcquat).t();
00415       cv::Mat ang_diff = -1*MatDiffAngle(mcrot, mgrot); 
00416 
00417       // idk why but this fixes the problem... 
00418       // this or the problem is at diffAngle with large +ve and -ve angles
00419       ang_diff.at<float>(2) = -ang_diff.at<float>(2); 
00420       return PBVSTwist(mcpos - mgpos, ang_diff);
00421 
00438     }
00439 
00440     cv::Mat MatDiffAngle(cv::Mat m0, cv::Mat m1)
00441     {
00442       cv::Mat ret = cv::Mat::zeros(m0.size(), CV_32F);
00443       if (m0.size() != m1.size())
00444         return ret;
00445       for (int i = 0; i < m0.rows; i++)
00446       {
00447         for (int j = 0; j < m0.cols; j++)
00448         {
00449           ret.at<float>(i,j) = diffAngle(m0.at<float>(i,j), m1.at<float>(i,j));
00450         }
00451       }
00452       return ret;
00453     }
00454 
00455     float diffAngle(float a0, float a1)
00456     {
00457       // assume they are from -pi to pi
00458       float t = a0 - a1;
00459       if (t > PI)
00460         t = t - 2*PI;
00461       else if (t < -PI)
00462         t = t + 2*PI;
00463       return t;
00464     }
00465 
00466     // compute twist in camera frame 
00467     visual_servo::VisualServoTwist IBVSTwist(std::vector<VSXYZ> desired, std::vector<VSXYZ> pts)
00468     {
00469       cv::Mat error_mat;
00470 
00471       // return 0 twist if number of features does not equal to that of desired features
00472       if (pts.size() != desired.size())
00473         return visual_servo::VisualServoTwist();
00474 
00475       // for all three features,
00476       for (unsigned int i = 0; i < desired.size(); i++) 
00477       {
00478         cv::Mat error = cv::Mat::zeros(2, 1, CV_32F);
00479         error.at<float>(0,0) = (pts.at(i)).camera.x - (desired.at(i)).camera.x;
00480         error.at<float>(1,0) = (pts.at(i)).camera.y - (desired.at(i)).camera.y;
00481         error_mat.push_back(error);
00482       }
00483       return IBVSTwist(desired, pts, error_mat);
00484     }
00485 
00486     // compute twist in camera frame 
00487     visual_servo::VisualServoTwist IBVSTwist(std::vector<VSXYZ> desired, std::vector<VSXYZ> pts, cv::Mat error_mat)
00488     {
00489       cv::Mat im;
00490       if (im.cols != 1 || im.rows != 6)
00491         im = im.reshape(1, 6);
00492 
00493       // return 0 twist if number of features does not equal to that of desired features
00494       if (pts.size() != desired.size())
00495         return visual_servo::VisualServoTwist();
00496 
00497       im = getMeterInteractionMatrix(pts);
00498       return computeTwist(error_mat, im, optical_frame_);
00499     }
00500 
00501     // override function to support PoseStamped
00502     visual_servo::VisualServoTwist IBVSTwist(std::vector<PoseStamped> desired, std::vector<PoseStamped> pts)
00503     {
00504       cv::Mat error_mat;
00505       cv::Mat im;
00506 
00507       // return 0 twist if number of features does not equal to that of desired features
00508       if (pts.size() != desired.size())
00509         return visual_servo::VisualServoTwist();
00510       //return cv::Mat::zeros(6, 1, CV_32F);
00511 
00512       // for all three features,
00513       for (unsigned int i = 0; i < desired.size(); i++)
00514       {
00515         cv::Mat error = cv::Mat::zeros(2, 1, CV_32F);
00516         error.at<float>(0,0) = (pts.at(i)).pose.position.x -
00517           (desired.at(i)).pose.position.x;
00518         error.at<float>(1,0) = (pts.at(i)).pose.position.y -
00519           (desired.at(i)).pose.position.y;
00520         error_mat.push_back(error);
00521       }
00522 
00523       im = getMeterInteractionMatrix(pts);
00524       std::string of = pts.at(0).header.frame_id;
00525       return computeTwist(error_mat, im, of);
00526     }
00527 
00528     visual_servo::VisualServoTwist computeTwist(cv::Mat error_mat, cv::Mat im, std::string optical_frame)
00529     {
00530       // if we can't compute interaction matrix, just make all twists 0
00531       if (countNonZero(im) == 0) return visual_servo::VisualServoTwist();
00532 
00533       // inverting the matrix, 3 approaches
00534       cv::Mat iim;
00535       switch (jacobian_type_)
00536       {
00537         case JACOBIAN_TYPE_INV:
00538           iim = (im).inv();
00539           break;
00540         case JACOBIAN_TYPE_PSEUDO:
00541           iim = pseudoInverse(im);
00542           break;
00543         default: // JACOBIAN_TYPE_AVG
00544           // We use specific way shown on visual servo by Chaumette 2006
00545 
00546           if (!desired_jacobian_set_)
00547             return visual_servo::VisualServoTwist();
00548 
00549           cv::Mat temp = desired_jacobian_ + im;
00550           iim = 0.5 * pseudoInverse(temp);
00551       }
00552 
00553       // Gain Matrix K (different from camera intrinsics)
00554       cv::Mat gain = cv::Mat::eye(6,6, CV_32F);
00555 
00556       // K x IIM x ERROR = TWIST
00557       cv::Mat temp = gain*iim*error_mat;
00558       return transformVelocity(temp);
00559     }
00560 
00561     cv::Mat pseudoInverse(cv::Mat im)
00562     {
00563       return (im.t() * im).inv()*im.t();
00564     }
00565 
00572     cv::Mat getMeterInteractionMatrix(std::vector<PoseStamped> &pts)
00573     {
00574       int size = (int)pts.size();
00575       // interaction matrix, image jacobian
00576       cv::Mat L = cv::Mat::zeros(size*2, 6,CV_32F);
00577       //if (pts.size() != 3) 
00578       //  return L;
00579       for (int i = 0; i < size; i++) {
00580         PoseStamped ps = pts.at(i);
00581         float x = ps.pose.position.x;
00582         float y = ps.pose.position.y;
00583         float Z = ps.pose.position.z;
00584         if (Z < 0.01 || Z > 0.95)
00585         {
00586           ROS_ERROR("Incorrect Z (%f). Cannot Compute Jacobian", Z);
00587           return cv::Mat::zeros(size*2, 6, CV_32F);
00588         }
00589         // float z = cur_point_cloud_.at(y,x).z;
00590         int l = i * 2;
00591         if (isnan(Z)) return cv::Mat::zeros(6,6, CV_32F);
00592         L.at<float>(l,0) = -1/Z;   L.at<float>(l+1,0) = 0;
00593         L.at<float>(l,1) = 0;      L.at<float>(l+1,1) = -1/Z;
00594         L.at<float>(l,2) = x/Z;    L.at<float>(l+1,2) = y/Z;
00595         L.at<float>(l,3) = x*y;    L.at<float>(l+1,3) = (1 + pow(y,2));
00596         L.at<float>(l,4) = -(1+pow(x,2));  L.at<float>(l+1,4) = -x*y;
00597         L.at<float>(l,5) = y;      L.at<float>(l+1,5) = -x;
00598       }
00599       return L;
00600     }
00601 
00602     cv::Mat getMeterInteractionMatrix(std::vector<VSXYZ> &pts) 
00603     {
00604       int size = (int)pts.size();
00605       // interaction matrix, image jacobian
00606       cv::Mat L = cv::Mat::zeros(size*2, 6,CV_32F);
00607       //if (pts.size() != 3) 
00608       //  return L;
00609       for (int i = 0; i < size; i++) {
00610         pcl::PointXYZ xyz= pts.at(i).camera;
00611         float x = xyz.x;
00612         float y = xyz.y;
00613         float Z = xyz.z;
00614         if (Z < 0.01 || Z > 0.95)
00615         {
00616           ROS_ERROR("Incorrect Z (%f). Cannot Compute Jacobian", Z);
00617           return cv::Mat::zeros(size*2, 6, CV_32F);
00618         }
00619         // float z = cur_point_cloud_.at(y,x).z;
00620         int l = i * 2;
00621         if (isnan(Z)) return cv::Mat::zeros(6,6, CV_32F);
00622         L.at<float>(l,0) = -1/Z;   L.at<float>(l+1,0) = 0;
00623         L.at<float>(l,1) = 0;      L.at<float>(l+1,1) = -1/Z;
00624         L.at<float>(l,2) = x/Z;    L.at<float>(l+1,2) = y/Z;
00625         L.at<float>(l,3) = x*y;    L.at<float>(l+1,3) = (1 + pow(y,2));
00626         L.at<float>(l,4) = -(1+pow(x,2));  L.at<float>(l+1,4) = -x*y;
00627         L.at<float>(l,5) = y;      L.at<float>(l+1,5) = -x;
00628       }
00629       return L;
00630     }
00631 
00632     /**************************** 
00633      * Projection & Conversions
00634      ****************************/
00641     cv::Mat projectImagePointToPoint(cv::Point in) 
00642     {
00643       if (K.rows == 0 || K.cols == 0) {
00644 
00645         // Camera intrinsic matrix
00646         K  = cv::Mat(cv::Size(3,3), CV_64F, &(cam_info_.K));
00647         K.convertTo(K, CV_32F);
00648       }
00649 
00650       cv::Mat k_inv = K.inv();
00651 
00652       cv::Mat mIn  = cv::Mat(3,1,CV_32F);
00653       mIn.at<float>(0,0) = in.x; 
00654       mIn.at<float>(1,0) = in.y; 
00655       mIn.at<float>(2,0) = 1; 
00656       return k_inv * mIn;
00657     }
00658 
00665     cv::Mat projectImageMatToPoint(cv::Mat in)
00666     {
00667       cv::Point p(in.at<float>(0,0), in.at<float>(1,0));
00668       return projectImagePointToPoint(p);
00669     }
00670     /*
00671     cv::Point projectPointIntoImage(pcl::PointXYZ cur_point_pcl,
00672         std::string point_frame, std::string target_frame, shared_ptr<tf::TransformListener> tf_)
00673     {
00674       PointStamped cur_point;
00675       cur_point.header.frame_id = point_frame;
00676       cur_point.point.x = cur_point_pcl.x;
00677       cur_point.point.y = cur_point_pcl.y;
00678       cur_point.point.z = cur_point_pcl.z;
00679       return projectPointIntoImage(cur_point, target_frame, tf_);
00680     }
00681 */
00682     cv::Point projectPointIntoImage(PointStamped cur_point,
00683         std::string target_frame, shared_ptr<tf::TransformListener> tf_)
00684     {
00685       if (K.rows == 0 || K.cols == 0) {
00686         // Camera intrinsic matrix
00687         K  = cv::Mat(cv::Size(3,3), CV_64F, &(cam_info_.K));
00688         K.convertTo(K, CV_32F);
00689       }
00690       cv::Point img_loc;
00691       try
00692       {
00693         // Transform point into the camera frame
00694         PointStamped image_frame_loc_m;
00695         tf_->transformPoint(target_frame, cur_point, image_frame_loc_m);
00696         // Project point onto the image
00697         img_loc.x = static_cast<int>((K.at<float>(0,0)*image_frame_loc_m.point.x +
00698               K.at<float>(0,2)*image_frame_loc_m.point.z) /
00699             image_frame_loc_m.point.z);
00700         img_loc.y = static_cast<int>((K.at<float>(1,1)*image_frame_loc_m.point.y +
00701               K.at<float>(1,2)*image_frame_loc_m.point.z) /
00702             image_frame_loc_m.point.z);
00703       }
00704       catch (tf::TransformException e)
00705       {
00706         ROS_ERROR_STREAM(e.what());
00707       }
00708       return img_loc;
00709     }
00710 
00711     float getZValue(cv::Mat depth_frame, int x, int y)
00712     {
00713       int window_size = 3;
00714       float value = 0;
00715       int size = 0; 
00716       for (int i = 0; i < window_size; i++) 
00717       {
00718         for (int j = 0; j < window_size; j++) 
00719         {
00720           // depth camera has x and y flipped. depth_frame.at(y,x)
00721           float temp = depth_frame.at<float>(y-(int)(window_size/2)+j, x-(int)(window_size/2)+i);
00722           // printf("[%d %d] %f\n", x-(int)(window_size/2)+i, y-(int)(window_size/2)+j, temp);
00723           if (!isnan(temp) && temp > 0 && temp < 2.0) 
00724           {
00725             size++;
00726             value += temp;
00727           }
00728           else
00729           {
00730           }
00731         }
00732       }
00733       if (size == 0)
00734         return -1;
00735       return value/size;
00736     }
00737 
00738     visual_servo::VisualServoTwist transformVelocity(cv::Mat in)
00739     {
00740       ros::Time now = ros::Time(0);
00741       listener_.lookupTransform(workspace_frame_, optical_frame_,  now, transform);
00742 
00743       // have to transform twist in camera frame (openni_rgb_optical_frame) to torso frame (torso_lift_link)
00744       tf::Vector3 twist_rot(in.at<float>(3), in.at<float>(4), in.at<float>(5));
00745       tf::Vector3 twist_vel(in.at<float>(0), in.at<float>(1), in.at<float>(2));
00746 
00747       // twist transformation from optical frame to workspace frame
00748       tf::Vector3 out_rot = transform.getBasis() * twist_rot;
00749       tf::Vector3 out_vel = transform.getBasis() * twist_vel + transform.getOrigin().cross(out_rot);
00750 
00751       std::vector<double> vels; 
00752       vels.push_back(out_vel.x()*gain_vel_);
00753       vels.push_back(out_vel.y()*gain_vel_);
00754       vels.push_back(out_vel.z()*gain_vel_);
00755       vels.push_back(out_rot.x()*gain_rot_);
00756       vels.push_back(out_rot.y()*gain_rot_);
00757       vels.push_back(out_rot.z()*gain_rot_);
00758       return VisualServoMsg::createTwistMsg(1.0, vels);
00759     }
00760 
00761     // DEBUG PURPOSE
00762     void printMatrix(cv::Mat_<double> in)
00763     {
00764       for (int i = 0; i < in.rows; i++) {
00765         for (int j = 0; j < in.cols; j++) {
00766           printf("%+.5f\t", in(i,j)); 
00767         }
00768         printf("\n");
00769       }
00770     }
00771 };


visual_servo
Author(s): Stephan Lee
autogenerated on Wed Nov 27 2013 11:44:03