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
00036 #include <ros/ros.h>
00037 #include <boost/scoped_ptr.hpp>
00038 #include <cmath>
00039
00040 #include <actionlib/server/action_server.h>
00041
00042 #include <kdl/chainfksolver.hpp>
00043 #include <kdl/chain.hpp>
00044 #include <kdl/chainjnttojacsolver.hpp>
00045 #include <kdl/chainfksolverpos_recursive.hpp>
00046 #include <kdl_parser/kdl_parser.hpp>
00047
00048 #include <tf_conversions/tf_kdl.h>
00049 #include <tf/transform_datatypes.h>
00050 #include <tf/transform_listener.h>
00051
00052 #include <urdf/model.h>
00053
00054 #include <trajectory_msgs/JointTrajectory.h>
00055 #include <control_msgs/PointHeadAction.h>
00056 #include <control_msgs/QueryTrajectoryState.h>
00057 #include <control_msgs/JointTrajectoryControllerState.h>
00058
00059 class ControlHead
00060 {
00061 private:
00062 typedef actionlib::ActionServer<control_msgs::PointHeadAction> PHAS;
00063 typedef PHAS::GoalHandle GoalHandle;
00064
00065 const std::string action_name_;
00066 std::string root_;
00067 std::string tip_;
00068 std::string pan_link_;
00069 std::string default_pointing_frame_;
00070 std::string pointing_frame_;
00071 tf::Vector3 pointing_axis_;
00072 std::vector< std::string> joint_names_;
00073
00074 ros::NodeHandle nh_, pnh_;
00075 ros::Publisher pub_controller_command_;
00076 ros::Subscriber sub_controller_state_;
00077 ros::ServiceClient cli_query_traj_;
00078 ros::Timer watchdog_timer_;
00079
00080 PHAS action_server_;
00081 bool has_active_goal_;
00082 GoalHandle active_goal_;
00083 double success_angle_threshold_;
00084
00085 KDL::Tree tree_;
00086 KDL::Chain chain_;
00087 tf::Point target_in_root_;
00088 tf::Vector3 desired_pointing_axis_in_frame_;
00089 double goal_error_;
00090
00091 boost::scoped_ptr<KDL::ChainFkSolverPos> pose_solver_;
00092 boost::scoped_ptr<KDL::ChainJntToJacSolver> jac_solver_;
00093
00094 tf::TransformListener tfl_;
00095 urdf::Model urdf_model_;
00096
00097 control_msgs::JointTrajectoryControllerStateConstPtr last_controller_state_;
00098
00099 public:
00100 ControlHead(const ros::NodeHandle &node)
00101 : action_name_("point_head_action")
00102 , nh_(node)
00103 , pnh_("~")
00104 , action_server_(nh_, action_name_.c_str(),
00105 boost::bind(&ControlHead::goalCB, this, _1),
00106 boost::bind(&ControlHead::cancelCB, this, _1), false)
00107 , has_active_goal_(false)
00108 {
00109 pnh_.param("pan_link", pan_link_, std::string("head_pan_link"));
00110 pnh_.param("default_pointing_frame", default_pointing_frame_, std::string("head_tilt_link"));
00111 pnh_.param("success_angle_threshold", success_angle_threshold_, 0.1);
00112
00113 if (pan_link_[0] == '/') pan_link_.erase(0, 1);
00114 if (default_pointing_frame_[0] == '/') default_pointing_frame_.erase(0, 1);
00115
00116
00117 pub_controller_command_ =
00118 nh_.advertise<trajectory_msgs::JointTrajectory>("command", 2);
00119 sub_controller_state_ =
00120 nh_.subscribe("state", 1, &ControlHead::controllerStateCB, this);
00121 cli_query_traj_ =
00122 nh_.serviceClient<control_msgs::QueryTrajectoryState>("query_state");
00123
00124 if (tree_.getNrOfJoints() == 0)
00125 {
00126 std::string robot_desc_string;
00127 std::string robot_desc_key;
00128 if(nh_.searchParam("robot_description", robot_desc_key))
00129 {
00130 ROS_INFO_STREAM("Load description from: " << robot_desc_key);
00131 nh_.param(robot_desc_key, robot_desc_string, std::string());
00132 }
00133 else
00134 {
00135 nh_.param("/robot_description", robot_desc_string, std::string());
00136 }
00137
00138 ROS_DEBUG("Reading tree from robot_description...");
00139 if (!kdl_parser::treeFromString(robot_desc_string, tree_))
00140 {
00141 ROS_ERROR("Failed to construct kdl tree");
00142 exit(-1);
00143 }
00144 if (!urdf_model_.initString(robot_desc_string))
00145 {
00146 ROS_ERROR("Failed to parse urdf string for urdf::Model.");
00147 exit(-2);
00148 }
00149 }
00150
00151 ROS_DEBUG("Tree has %d joints and %d segments.", tree_.getNrOfJoints(), tree_.getNrOfSegments());
00152 action_server_.start();
00153 watchdog_timer_ = nh_.createTimer(ros::Duration(1.0), &ControlHead::watchdog, this);
00154 }
00155
00156 void goalCB(GoalHandle gh)
00157 {
00158
00159 if (root_.empty())
00160 {
00161 for (int i = 0; i < 10; ++i)
00162 {
00163 try
00164 {
00165 tfl_.getParent(pan_link_, ros::Time(), root_);
00166 break;
00167 }
00168 catch (const tf::TransformException &ex) {}
00169 ros::Duration(0.5).sleep();
00170 }
00171 if (root_.empty())
00172 {
00173 ROS_ERROR("Could not get parent of %s in the TF tree", pan_link_.c_str());
00174 gh.setRejected();
00175 return;
00176 }
00177 }
00178 if (root_[0] == '/') root_.erase(0, 1);
00179
00180 ROS_DEBUG("Got point head goal!");
00181
00182
00183 const geometry_msgs::PointStamped &target = gh.getGoal()->target;
00184 pointing_frame_ = gh.getGoal()->pointing_frame;
00185 if (pointing_frame_.length() == 0)
00186 {
00187 ROS_WARN("Pointing frame not specified, using %s [1, 0, 0] by default.", default_pointing_frame_.c_str());
00188 pointing_frame_ = default_pointing_frame_;
00189 pointing_axis_ = tf::Vector3(1.0, 0.0, 0.0);
00190 }
00191 else
00192 {
00193 if (pointing_frame_[0] == '/') pointing_frame_.erase(0, 1);
00194 bool ret1 = false;
00195 try
00196 {
00197 ret1 = tfl_.waitForTransform(pan_link_, pointing_frame_, target.header.stamp,
00198 ros::Duration(5.0), ros::Duration(0.01));
00199
00200 tf::vector3MsgToTF(gh.getGoal()->pointing_axis, pointing_axis_);
00201 if (pointing_axis_.length() < 0.1)
00202 {
00203 size_t found = pointing_frame_.find("optical_frame");
00204 if (found != std::string::npos)
00205 {
00206 ROS_WARN("Pointing axis appears to be zero-length. Using [0, 0, 1] as default for an optical frame.");
00207 pointing_axis_ = tf::Vector3(0, 0, 1);
00208 }
00209 else
00210 {
00211 ROS_WARN("Pointing axis appears to be zero-length. Using [1, 0, 0] as default for a non-optical frame.");
00212 pointing_axis_ = tf::Vector3(1, 0, 0);
00213 }
00214 }
00215 else
00216 {
00217 pointing_axis_.normalize();
00218 }
00219 }
00220 catch (const tf::TransformException &ex)
00221 {
00222 ROS_ERROR("Transform failure (%d): %s", ret1, ex.what());
00223 gh.setRejected();
00224 return;
00225 }
00226 }
00227
00228
00229 bool ret1 = false;
00230 try
00231 {
00232 std::string error_msg;
00233 ret1 = tfl_.waitForTransform(root_.c_str(), target.header.frame_id, target.header.stamp,
00234 ros::Duration(5.0), ros::Duration(0.01), &error_msg);
00235
00236 geometry_msgs::PointStamped target_in_root_msg;
00237 tfl_.transformPoint(root_.c_str(), target, target_in_root_msg );
00238 tf::pointMsgToTF(target_in_root_msg.point, target_in_root_);
00239 ROS_DEBUG_STREAM("Target point in base frame: (" << target_in_root_[0] << ", " << target_in_root_[1] << ", " << target_in_root_[2] << ")");
00240 }
00241 catch (const tf::TransformException &ex)
00242 {
00243 ROS_ERROR("Transform failure (%d): %s", ret1, ex.what());
00244 gh.setRejected();
00245 return;
00246 }
00247
00248 if (tip_.compare(pointing_frame_) != 0)
00249 {
00250 bool success = tree_.getChain(root_.c_str(), pointing_frame_.c_str(), chain_);
00251 if (!success)
00252 {
00253 ROS_ERROR("Couldn't create chain from %s to %s.", root_.c_str(), pointing_frame_.c_str());
00254 gh.setRejected();
00255 return;
00256 }
00257 tip_ = pointing_frame_;
00258
00259 pose_solver_.reset(new KDL::ChainFkSolverPos_recursive(chain_));
00260 jac_solver_.reset(new KDL::ChainJntToJacSolver(chain_));
00261 joint_names_.resize(chain_.getNrOfJoints());
00262 }
00263
00264 const unsigned int joints = chain_.getNrOfJoints();
00265
00266 KDL::JntArray jnt_pos(joints), jnt_eff(joints);
00267 KDL::Jacobian jacobian(joints);
00268
00269 control_msgs::QueryTrajectoryState traj_state;
00270 traj_state.request.time = ros::Time::now() + ros::Duration(0.01);
00271 if (!cli_query_traj_.call(traj_state))
00272 {
00273 ROS_ERROR("Service call to query controller trajectory failed.");
00274 gh.setRejected();
00275 return;
00276 }
00277 if (traj_state.response.name.size() != joints)
00278 {
00279 ROS_ERROR("Number of joints mismatch: urdf chain vs. trajectory controller state.");
00280 gh.setRejected();
00281 return;
00282 }
00283 std::vector<urdf::JointLimits> limits_(joints);
00284
00285
00286 for (unsigned int i = 0; i < joints; ++i)
00287 {
00288 joint_names_[i] = traj_state.response.name[i];
00289 limits_[i] = *(urdf_model_.joints_[joint_names_[i].c_str()]->limits);
00290 ROS_DEBUG("Joint %d %s: %f, limits: %f %f", i, traj_state.response.name[i].c_str(), traj_state.response.position[i], limits_[i].lower, limits_[i].upper);
00291 jnt_pos(i) = 0;
00292 }
00293
00294 int count = 0;
00295 int limit_flips = 0;
00296 float correction_angle = 2*M_PI;
00297 float correction_delta = 2*M_PI;
00298 const int MAX_ITERATIONS = 15;
00299 while( ros::ok() &&
00300 fabs(correction_delta) > 0.001 &&
00301 count < MAX_ITERATIONS)
00302 {
00303
00304 KDL::Frame pose;
00305 pose_solver_->JntToCart(jnt_pos, pose);
00306 jac_solver_->JntToJac(jnt_pos, jacobian);
00307
00308 tf::Transform frame_in_root;
00309 tf::poseKDLToTF(pose, frame_in_root);
00310
00311 tf::Vector3 axis_in_frame = pointing_axis_.normalized();
00312 tf::Vector3 target_from_frame = (target_in_root_ - frame_in_root.getOrigin()).normalized();
00313 tf::Vector3 current_in_frame = frame_in_root.getBasis().inverse()*target_from_frame;
00314 float prev_correction = correction_angle;
00315 correction_angle = current_in_frame.angle(axis_in_frame);
00316 correction_delta = correction_angle - prev_correction;
00317
00318 ROS_DEBUG("At step %d, joint poses are %.4f and %.4f, angle error is %f radians", count, jnt_pos(0), jnt_pos(1), correction_angle);
00319 goal_error_ = correction_angle;
00320 if ( correction_angle < 0.5*success_angle_threshold_ )
00321 {
00322 ROS_DEBUG_STREAM("Accepting solution as estimated error is: " << correction_angle*180.0/M_PI << "degrees and stopping condition is half of " << success_angle_threshold_*180.0/M_PI);
00323 break;
00324 }
00325 tf::Vector3 correction_axis = frame_in_root.getBasis()*(axis_in_frame.cross(current_in_frame).normalized());
00326 tf::Transform correction_tf(tf::Quaternion(correction_axis, 0.5*correction_angle), tf::Vector3(0,0,0));
00327 KDL::Frame correction_kdl;
00328 tf::transformTFToKDL(correction_tf, correction_kdl);
00329
00330
00331 KDL::Frame identity_kdl;
00332 KDL::Twist twist = diff(correction_kdl, identity_kdl);
00333 KDL::Wrench wrench_desi;
00334 for (unsigned int i=0; i<6; ++i)
00335 wrench_desi(i) = -1.0*twist(i);
00336
00337
00338 for (unsigned int i = 0; i < joints; ++i)
00339 {
00340 jnt_eff(i) = 0;
00341 for (unsigned int j=0; j<6; ++j)
00342 jnt_eff(i) += (jacobian(j,i) * wrench_desi(j));
00343 jnt_pos(i) += jnt_eff(i);
00344 }
00345
00346
00347
00348
00349
00350
00351 jnt_pos(0) = std::max(limits_[0].lower, jnt_pos(0));
00352 jnt_pos(0) = std::min(limits_[0].upper, jnt_pos(0));
00353 jnt_pos(1) = std::max(limits_[1].lower, jnt_pos(1));
00354 jnt_pos(1) = std::min(limits_[1].upper, jnt_pos(1));
00355
00356 count++;
00357
00358 if (limit_flips > 1)
00359 {
00360 ROS_ERROR("Goal is out of joint limits, trying to point there anyway... \n");
00361 break;
00362 }
00363 }
00364 ROS_DEBUG_STREAM("Iterative solver took " << count << " steps. Expected error: " << correction_angle << " radians");
00365 if ( count == MAX_ITERATIONS )
00366 ROS_WARN("Aborted because maximum number of iterations was reached");
00367
00368 std::vector<double> q_goal(joints);
00369
00370
00371 for(unsigned int i = 0; i < joints; i++)
00372 {
00373 jnt_pos(i) = std::max(limits_[i].lower, jnt_pos(i));
00374 jnt_pos(i) = std::min(limits_[i].upper, jnt_pos(i));
00375 q_goal[i] = jnt_pos(i);
00376 ROS_DEBUG("Joint %d %s: %f", i, joint_names_[i].c_str(), jnt_pos(i));
00377 }
00378
00379
00380
00381 KDL::Frame pose;
00382 pose_solver_->JntToCart(jnt_pos, pose);
00383
00384 tf::Transform frame_in_root;
00385 tf::poseKDLToTF(pose, frame_in_root);
00386 tf::Vector3 target_from_frame = target_in_root_ - frame_in_root.getOrigin();
00387 target_from_frame.normalize();
00388 ROS_DEBUG_STREAM("BEFORE applying joint limits => desired pointing axis = (" <<
00389 pointing_axis_[0] << ", " <<
00390 pointing_axis_[1] << ", " <<
00391 pointing_axis_[2] << ")");
00392 desired_pointing_axis_in_frame_ = frame_in_root.getBasis().inverse()*target_from_frame;
00393 ROS_DEBUG_STREAM("AFTER applying joint limits => desired pointing axis = (" <<
00394 desired_pointing_axis_in_frame_[0] << ", " <<
00395 desired_pointing_axis_in_frame_[1] << ", " <<
00396 desired_pointing_axis_in_frame_[2] << ")");
00397
00398
00399
00400
00401
00402 goal_error_ = std::max(goal_error_, success_angle_threshold_);
00403 ROS_DEBUG_STREAM("the goal will terminate when error is: " << goal_error_*180.0/M_PI << " degrees => " << goal_error_ << " radians");
00404
00405 if (has_active_goal_)
00406 {
00407 active_goal_.setCanceled();
00408 has_active_goal_ = false;
00409 }
00410
00411 gh.setAccepted();
00412 active_goal_ = gh;
00413 has_active_goal_ = true;
00414
00415
00416 ros::Duration min_duration(0.01);
00417
00418 if (gh.getGoal()->min_duration > min_duration)
00419 min_duration = gh.getGoal()->min_duration;
00420
00421
00422 if (gh.getGoal()->max_velocity > 0)
00423 {
00424
00425 double largest_rotation = 0;
00426 for(unsigned int i = 0; i < joints; i++)
00427 {
00428 double required_rotation = fabs(q_goal[i] - traj_state.response.position[i]);
00429 if ( required_rotation > largest_rotation )
00430 largest_rotation = required_rotation;
00431 }
00432
00433 ros::Duration limit_from_velocity(largest_rotation / gh.getGoal()->max_velocity);
00434 if (limit_from_velocity > min_duration)
00435 min_duration = limit_from_velocity;
00436 }
00437
00438
00439 trajectory_msgs::JointTrajectory traj;
00440 traj.header.stamp = traj_state.request.time;
00441
00442 traj.joint_names.push_back(traj_state.response.name[0]);
00443 traj.joint_names.push_back(traj_state.response.name[1]);
00444
00445 traj.points.resize(1);
00446 traj.points[0].positions = q_goal;
00447 traj.points[0].velocities.push_back(0);
00448 traj.points[0].velocities.push_back(0);
00449 traj.points[0].time_from_start = ros::Duration(min_duration);
00450
00451
00452 pub_controller_command_.publish(traj);
00453 }
00454
00455 void watchdog(const ros::TimerEvent &e)
00456 {
00457 const ros::Time now = ros::Time::now();
00458
00459
00460 if (has_active_goal_)
00461 {
00462 bool should_abort = false;
00463 if (!last_controller_state_)
00464 {
00465 should_abort = true;
00466 ROS_WARN("Aborting goal because we have never heard a controller state message.");
00467 }
00468 else if ((now - last_controller_state_->header.stamp) > ros::Duration(5.0))
00469 {
00470 should_abort = true;
00471 ROS_WARN("Aborting goal because we haven't heard from the controller in %.3lf seconds",
00472 (now - last_controller_state_->header.stamp).toSec());
00473 }
00474
00475 if (should_abort)
00476 {
00477
00478 trajectory_msgs::JointTrajectory empty;
00479 empty.joint_names = joint_names_;
00480 pub_controller_command_.publish(empty);
00481
00482
00483 active_goal_.setAborted();
00484 has_active_goal_ = false;
00485 }
00486 }
00487 }
00488
00489 void cancelCB(GoalHandle gh)
00490 {
00491 if (active_goal_ == gh)
00492 {
00493
00494 trajectory_msgs::JointTrajectory empty;
00495 empty.joint_names = joint_names_;
00496 pub_controller_command_.publish(empty);
00497
00498
00499 active_goal_.setCanceled();
00500 has_active_goal_ = false;
00501 }
00502 }
00503
00504 void controllerStateCB(const control_msgs::JointTrajectoryControllerStateConstPtr &msg)
00505 {
00506 last_controller_state_ = msg;
00507 const ros::Time now = ros::Time::now();
00508
00509 if (!has_active_goal_)
00510 return;
00511
00513 try
00514 {
00515
00516 KDL::JntArray jnt_pos(msg->joint_names.size());
00517 for (size_t i = 0; i < msg->joint_names.size(); ++i)
00518 {
00519 jnt_pos(i) = msg->actual.positions[i];
00520 ROS_DEBUG_STREAM("current state of joint " << i << ": " << jnt_pos(i));
00521 }
00522
00523 KDL::Frame pose;
00524 pose_solver_->JntToCart(jnt_pos, pose);
00525
00526 tf::Transform frame_in_root;
00527 tf::poseKDLToTF(pose, frame_in_root);
00528
00529 tf::Vector3 axis_in_frame = pointing_axis_.normalized();
00530 tf::Vector3 target_from_frame = target_in_root_ - frame_in_root.getOrigin();
00531
00532 target_from_frame.normalize();
00533 tf::Vector3 current_in_frame = frame_in_root.getBasis().inverse()*target_from_frame;
00534
00535 control_msgs::PointHeadFeedback feedback;
00536 feedback.pointing_angle_error = current_in_frame.angle(desired_pointing_axis_in_frame_);
00537
00538 ROS_DEBUG_STREAM("current error is: " << feedback.pointing_angle_error << " radians");
00539
00540 active_goal_.publishFeedback(feedback);
00541
00542
00543
00544 if (feedback.pointing_angle_error <= goal_error_)
00545 {
00546 ROS_DEBUG_STREAM("goal succeeded with error: " << feedback.pointing_angle_error << " radians");
00547 active_goal_.setSucceeded();
00548 has_active_goal_ = false;
00549 }
00550 }
00551 catch (const tf::TransformException &ex)
00552 {
00553 ROS_ERROR("Could not transform: %s", ex.what());
00554 }
00555 }
00556 };
00557
00558 int main(int argc, char** argv)
00559 {
00560 ros::init(argc, argv, "point_head_action");
00561 ros::NodeHandle node;
00562 ControlHead ch(node);
00563 ros::spin();
00564 return 0;
00565 }