look_to_point.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (Modified BSD License)
00003  *
00004  *  Copyright (c) 2013, PAL Robotics, S.L.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of PAL Robotics, S.L. nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  */
00034 
00052 // C++ standard headers
00053 #include <exception>
00054 #include <string>
00055 
00056 // Boost headers
00057 #include <boost/shared_ptr.hpp>
00058 
00059 // ROS headers
00060 #include <ros/ros.h>
00061 #include <image_transport/image_transport.h>
00062 #include <actionlib/client/simple_action_client.h>
00063 #include <sensor_msgs/CameraInfo.h>
00064 #include <geometry_msgs/PointStamped.h>
00065 #include <control_msgs/PointHeadAction.h>
00066 #include <sensor_msgs/image_encodings.h>
00067 #include <ros/topic.h>
00068 
00069 // OpenCV headers
00070 #include <opencv2/highgui/highgui.hpp>
00071 #include <cv_bridge/cv_bridge.h>
00072 
00074 
00075 static const std::string windowName      = "Inside of TIAGo's head";
00076 static const std::string cameraFrame     = "/xtion_rgb_optical_frame";
00077 static const std::string imageTopic      = "/xtion/rgb/image_raw";
00078 static const std::string cameraInfoTopic = "/xtion/rgb/camera_info";
00079 
00080 // Intrinsic parameters of the camera
00081 cv::Mat cameraIntrinsics;
00082 
00083 // Our Action interface type for moving TIAGo's head, provided as a typedef for convenience
00084 typedef actionlib::SimpleActionClient<control_msgs::PointHeadAction> PointHeadClient;
00085 typedef boost::shared_ptr<PointHeadClient> PointHeadClientPtr;
00086 
00087 PointHeadClientPtr pointHeadClient;
00088 
00089 ros::Time latestImageStamp;
00090 
00092 
00093 // ROS call back for every new image received
00094 void imageCallback(const sensor_msgs::ImageConstPtr& imgMsg)
00095 {
00096   latestImageStamp = imgMsg->header.stamp;
00097 
00098   cv_bridge::CvImagePtr cvImgPtr;
00099 
00100   cvImgPtr = cv_bridge::toCvCopy(imgMsg, sensor_msgs::image_encodings::BGR8);
00101   cv::imshow(windowName, cvImgPtr->image);
00102   cv::waitKey(15);
00103 }
00104 
00105 // OpenCV callback function for mouse events on a window
00106 void onMouse( int event, int u, int v, int, void* )
00107 {
00108   if ( event != cv::EVENT_LBUTTONDOWN )
00109       return;
00110 
00111   ROS_INFO_STREAM("Pixel selected (" << u << ", " << v << ") Making TIAGo look to that direction");
00112 
00113   geometry_msgs::PointStamped pointStamped;
00114 
00115   pointStamped.header.frame_id = cameraFrame;
00116   pointStamped.header.stamp    = latestImageStamp;
00117 
00118   //compute normalized coordinates of the selected pixel
00119   double x = ( u  - cameraIntrinsics.at<double>(0,2) )/ cameraIntrinsics.at<double>(0,0);
00120   double y = ( v  - cameraIntrinsics.at<double>(1,2) )/ cameraIntrinsics.at<double>(1,1);
00121   double Z = 1.0; //define an arbitrary distance
00122   pointStamped.point.x = x * Z;
00123   pointStamped.point.y = y * Z;
00124   pointStamped.point.z = Z;   
00125 
00126   //build the action goal
00127   control_msgs::PointHeadGoal goal;
00128   //the goal consists in making the Z axis of the cameraFrame to point towards the pointStamped
00129   goal.pointing_frame = cameraFrame;
00130   goal.pointing_axis.x = 0.0;
00131   goal.pointing_axis.y = 0.0;
00132   goal.pointing_axis.z = 1.0;
00133   goal.min_duration = ros::Duration(1.0);
00134   goal.max_velocity = 0.25;
00135   goal.target = pointStamped;
00136 
00137   pointHeadClient->sendGoal(goal);
00138   ros::Duration(0.5).sleep();
00139 }
00140 
00141 // Create a ROS action client to move TIAGo's head
00142 void createPointHeadClient(PointHeadClientPtr& actionClient)
00143 {
00144   ROS_INFO("Creating action client to head controller ...");
00145 
00146   actionClient.reset( new PointHeadClient("/head_controller/point_head_action") );
00147 
00148   int iterations = 0, max_iterations = 3;
00149   // Wait for head controller action server to come up
00150   while( !actionClient->waitForServer(ros::Duration(2.0)) && ros::ok() && iterations < max_iterations )
00151   {
00152     ROS_DEBUG("Waiting for the point_head_action server to come up");
00153     ++iterations;
00154   }
00155 
00156   if ( iterations == max_iterations )
00157     throw std::runtime_error("Error in createPointHeadClient: head controller action server not available");
00158 }
00159 
00161 
00162 // Entry point
00163 int main(int argc, char** argv)
00164 {
00165   // Init the ROS node
00166   ros::init(argc, argv, "look_to_point");
00167 
00168   ROS_INFO("Starting look_to_point application ...");
00169  
00170   // Precondition: Valid clock
00171   ros::NodeHandle nh;
00172   if (!ros::Time::waitForValid(ros::WallDuration(10.0))) // NOTE: Important when using simulated clock
00173   {
00174     ROS_FATAL("Timed-out waiting for valid time.");
00175     return EXIT_FAILURE;
00176   }
00177 
00178   // Get the camera intrinsic parameters from the appropriate ROS topic
00179   ROS_INFO("Waiting for camera intrinsics ... ");
00180   sensor_msgs::CameraInfoConstPtr msg = ros::topic::waitForMessage
00181       <sensor_msgs::CameraInfo>(cameraInfoTopic, ros::Duration(10.0));
00182   if(msg.use_count() > 0)
00183   {
00184     cameraIntrinsics = cv::Mat::zeros(3,3,CV_64F);
00185     cameraIntrinsics.at<double>(0, 0) = msg->K[0]; //fx
00186     cameraIntrinsics.at<double>(1, 1) = msg->K[4]; //fy
00187     cameraIntrinsics.at<double>(0, 2) = msg->K[2]; //cx
00188     cameraIntrinsics.at<double>(1, 2) = msg->K[5]; //cy
00189     cameraIntrinsics.at<double>(2, 2) = 1;
00190   }
00191 
00192   // Create a point head action client to move the TIAGo's head
00193   createPointHeadClient( pointHeadClient );
00194 
00195   // Create the window to show TIAGo's camera images
00196   cv::namedWindow(windowName, cv::WINDOW_AUTOSIZE);
00197 
00198   // Set mouse handler for the window
00199   cv::setMouseCallback(windowName, onMouse);
00200 
00201   // Define ROS topic from where TIAGo publishes images
00202   image_transport::ImageTransport it(nh);
00203   // use compressed image transport to use less network bandwidth
00204   image_transport::TransportHints transportHint("compressed");
00205 
00206   ROS_INFO_STREAM("Subscribing to " << imageTopic << " ...");
00207   image_transport::Subscriber sub = it.subscribe(imageTopic, 1,
00208                                                  imageCallback, transportHint);
00209 
00210   //enter a loop that processes ROS callbacks. Press CTRL+C to exit the loop
00211   ros::spin();
00212 
00213   cv::destroyWindow(windowName);
00214 
00215   return EXIT_SUCCESS;
00216 }


look_to_point
Author(s):
autogenerated on Fri Aug 26 2016 13:20:13