00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 #include <cmath>
00036 
00037 #include <ros/ros.h>
00038 #include <message_filters/subscriber.h>
00039 #include <tf/message_filter.h>
00040 #include <tf/transform_listener.h>
00041 #include <actionlib/server/action_server.h>
00042 
00043 #include <geometry_msgs/PointStamped.h>
00044 #include <trajectory_msgs/JointTrajectory.h>
00045 #include <pr2_controllers_msgs/PointHeadAction.h>
00046 #include <pr2_controllers_msgs/QueryTrajectoryState.h>
00047 #include <pr2_controllers_msgs/JointTrajectoryControllerState.h>
00048 
00049 class ControlHead
00050 {
00051 private:
00052   typedef actionlib::ActionServer<pr2_controllers_msgs::PointHeadAction> PHAS;
00053   typedef PHAS::GoalHandle GoalHandle;
00054 public:
00055   ControlHead(const ros::NodeHandle &n)
00056     : node_(n),
00057       action_server_(node_, "point_head_action",
00058                      boost::bind(&ControlHead::goalCB, this, _1),
00059                      boost::bind(&ControlHead::cancelCB, this, _1)),
00060       has_active_goal_(false)
00061   {
00062     ros::NodeHandle pn("~");
00063     pn.param("pan_link", pan_link_, std::string("head_pan_link"));
00064     pn.param("tilt_link", tilt_link_, std::string("head_tilt_link"));
00065     pn.param("success_angle_threshold", success_angle_threshold_, 0.1);
00066 
00067     
00068     pan_joint_ = "head_pan_joint";
00069     tilt_joint_ = "head_tilt_joint";
00070 
00071     std::vector<std::string> frames;
00072     frames.push_back(pan_link_);
00073     frames.push_back(tilt_link_);
00074 
00075     
00076     pub_controller_command_ =
00077       node_.advertise<trajectory_msgs::JointTrajectory>("command", 2);
00078     sub_controller_state_ =
00079       node_.subscribe("state", 1, &ControlHead::controllerStateCB, this);
00080     cli_query_traj_ =
00081       node_.serviceClient<pr2_controllers_msgs::QueryTrajectoryState>("query_state");
00082 
00083     watchdog_timer_ = node_.createTimer(ros::Duration(1.0), &ControlHead::watchdog, this);
00084   }
00085 
00086 
00087   void goalCB(GoalHandle gh)
00088   {
00089     
00090     if (pan_parent_.empty())
00091     {
00092       for (int i = 0; i < 10; ++i)
00093       {
00094         try {
00095           tf_.getParent(pan_link_, ros::Time(), pan_parent_);
00096           break;
00097         }
00098         catch (const tf::TransformException &ex) {}
00099         ros::Duration(0.5).sleep();
00100       }
00101 
00102       if (pan_parent_.empty())
00103       {
00104         ROS_ERROR("Could not get parent of %s in the TF tree", pan_link_.c_str());
00105         gh.setRejected();
00106         return;
00107       }
00108     }
00109 
00110 
00111     std::vector<double> q_goal(2);  
00112 
00113     
00114     const geometry_msgs::PointStamped &target = gh.getGoal()->target;
00115     bool ret1 = false, ret2 = false;
00116     try {
00117       ros::Time now = ros::Time::now();
00118       std::string error_msg;
00119       ret1 = tf_.waitForTransform(pan_parent_, target.header.frame_id, target.header.stamp,
00120                                  ros::Duration(5.0), ros::Duration(0.01), &error_msg);
00121       ret2 = tf_.waitForTransform(pan_link_, target.header.frame_id, target.header.stamp,
00122                                    ros::Duration(5.0), ros::Duration(0.01), &error_msg);
00123 
00124       
00125 
00126       
00127       tf::Stamped<tf::Point> target_point, target_in_tilt;
00128       tf::pointStampedMsgToTF(target, target_point);
00129       tf_.transformPoint(pan_parent_, target_point, target_in_pan_);
00130       tf_.transformPoint(pan_link_, target_point, target_in_tilt);
00131 
00132       
00133       q_goal[0] = atan2(target_in_pan_.y(), target_in_pan_.x());
00134       q_goal[1] = atan2(-target_in_tilt.z(),
00135                         sqrt(pow(target_in_tilt.x(),2) + pow(target_in_tilt.y(),2)));
00136     }
00137     catch(const tf::TransformException &ex)
00138     {
00139       ROS_ERROR("Transform failure (%d,%d): %s", ret1, ret2, ex.what());
00140       gh.setRejected();
00141       return;
00142     }
00143 
00144     
00145     pr2_controllers_msgs::QueryTrajectoryState traj_state;
00146     traj_state.request.time = ros::Time::now() + ros::Duration(0.01);
00147     if (!cli_query_traj_.call(traj_state))
00148     {
00149       ROS_ERROR("Service call to query controller trajectory failed.");
00150       return;
00151     }
00152 
00153     if (has_active_goal_)
00154     {
00155       active_goal_.setCanceled();
00156       has_active_goal_ = false;
00157     }
00158 
00159     gh.setAccepted();
00160     active_goal_ = gh;
00161     has_active_goal_ = true;
00162 
00163     
00164 
00165     ros::Duration min_duration(0.01);
00166 
00167     if (gh.getGoal()->min_duration > min_duration)
00168         min_duration = gh.getGoal()->min_duration;
00169 
00170     
00171     
00172     if (gh.getGoal()->max_velocity > 0)
00173     {
00174       
00175       double dist = sqrt(pow(q_goal[0] - traj_state.response.position[0], 2) +
00176                          pow(q_goal[1] - traj_state.response.position[1], 2));
00177       ros::Duration limit_from_velocity(dist / gh.getGoal()->max_velocity);
00178       if (limit_from_velocity > min_duration)
00179         min_duration = limit_from_velocity;
00180     }
00181 
00182     
00183     trajectory_msgs::JointTrajectory traj;
00184     traj.header.stamp = traj_state.request.time;
00185 
00186     traj.joint_names.push_back(pan_joint_);
00187     traj.joint_names.push_back(tilt_joint_);
00188 
00189     traj.points.resize(2);
00190     traj.points[0].positions = traj_state.response.position;
00191     traj.points[0].velocities = traj_state.response.velocity;
00192     traj.points[0].time_from_start = ros::Duration(0.0);
00193     traj.points[1].positions = q_goal;
00194     traj.points[1].velocities.push_back(0);
00195     traj.points[1].velocities.push_back(0);
00196     traj.points[1].time_from_start = ros::Duration(min_duration);
00197 
00198     pub_controller_command_.publish(traj);
00199   }
00200 
00201 
00202 private:
00203   std::string pan_link_;
00204   std::string tilt_link_;
00205   std::string pan_joint_;
00206   std::string tilt_joint_;
00207 
00208   ros::NodeHandle node_;
00209   tf::TransformListener tf_;
00210   ros::Publisher pub_controller_command_;
00211   ros::Subscriber sub_controller_state_;
00212   ros::Subscriber command_sub_;
00213   ros::ServiceClient cli_query_traj_;
00214   ros::Timer watchdog_timer_;
00215 
00216   PHAS action_server_;
00217   bool has_active_goal_;
00218   GoalHandle active_goal_;
00219   tf::Stamped<tf::Point> target_in_pan_;
00220   std::string pan_parent_;
00221   double success_angle_threshold_;
00222 
00223   void watchdog(const ros::TimerEvent &e)
00224   {
00225     ros::Time now = ros::Time::now();
00226 
00227     
00228     if (has_active_goal_)
00229     {
00230       bool should_abort = false;
00231       if (!last_controller_state_)
00232       {
00233         should_abort = true;
00234         ROS_WARN("Aborting goal because we have never heard a controller state message.");
00235       }
00236       else if ((now - last_controller_state_->header.stamp) > ros::Duration(5.0))
00237       {
00238         should_abort = true;
00239         ROS_WARN("Aborting goal because we haven't heard from the controller in %.3lf seconds",
00240                  (now - last_controller_state_->header.stamp).toSec());
00241       }
00242 
00243       if (should_abort)
00244       {
00245         
00246         trajectory_msgs::JointTrajectory empty;
00247         empty.joint_names.push_back(pan_joint_);
00248         empty.joint_names.push_back(tilt_joint_);
00249         pub_controller_command_.publish(empty);
00250 
00251         
00252         active_goal_.setAborted();
00253         has_active_goal_ = false;
00254       }
00255     }
00256   }
00257 
00258   void cancelCB(GoalHandle gh)
00259   {
00260     if (active_goal_ == gh)
00261     {
00262       
00263       trajectory_msgs::JointTrajectory empty;
00264       empty.joint_names.push_back(pan_joint_);
00265       empty.joint_names.push_back(tilt_joint_);
00266       pub_controller_command_.publish(empty);
00267 
00268       
00269       active_goal_.setCanceled();
00270       has_active_goal_ = false;
00271     }
00272   }
00273 
00274   pr2_controllers_msgs::JointTrajectoryControllerStateConstPtr last_controller_state_;
00275   void controllerStateCB(const pr2_controllers_msgs::JointTrajectoryControllerStateConstPtr &msg)
00276   {
00277     last_controller_state_ = msg;
00278     ros::Time now = ros::Time::now();
00279 
00280     if (!has_active_goal_)
00281       return;
00282 
00284     try
00285     {
00286       tf::Stamped<tf::Vector3> origin(tf::Vector3(0,0,0), msg->header.stamp, tilt_link_);
00287       tf::Stamped<tf::Vector3> forward(tf::Vector3(1,0,0), msg->header.stamp, tilt_link_);
00288       tf_.waitForTransform(pan_parent_, tilt_link_, msg->header.stamp, ros::Duration(1.0));
00289       tf_.transformPoint(pan_parent_, origin, origin);
00290       tf_.transformPoint(pan_parent_, forward, forward);
00291       pr2_controllers_msgs::PointHeadFeedback feedback;
00292       feedback.pointing_angle_error =
00293         (forward - origin).angle(target_in_pan_ - origin);
00294       active_goal_.publishFeedback(feedback);
00295 
00296       if (feedback.pointing_angle_error < success_angle_threshold_)
00297       {
00298         active_goal_.setSucceeded();
00299         has_active_goal_ = false;
00300       }
00301     }
00302     catch(const tf::TransformException &ex)
00303     {
00304       ROS_ERROR("Could not transform: %s", ex.what());
00305     }
00306   }
00307 
00308 };
00309 
00310 int main(int argc, char** argv)
00311 {
00312   ros::init(argc, argv, "point_head_action");
00313   ros::NodeHandle node;
00314   ControlHead ch(node);
00315   ros::spin();
00316   return 0;
00317 }