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 }