move_arm_head_monitor.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  *
00003  * Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2010, Willow Garage, Inc.
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/or other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of the Willow Garage nor the names of its
00019  *     contributors may be used to endorse or promote products derived
00020  *     from this software without specific prior written permission.
00021  *
00022  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033  *  POSSIBILITY OF SUCH DAMAGE.
00034  *
00035  *  \author Adam Harmat, E. Gil Jones
00036  *********************************************************************/
00037 
00038 #include <ros/ros.h>
00039 
00040 #include <planning_environment/models/collision_models_interface.h>
00041 #include <planning_environment/monitors/kinematic_model_state_monitor.h>
00042 #include <planning_environment/models/model_utils.h>
00043 #include <planning_environment/monitors/monitor_utils.h>
00044 #include <arm_navigation_msgs/convert_messages.h>
00045 #include "planning_environment/util/construct_object.h"
00046 
00047 #include <sensor_msgs/PointCloud2.h>
00048 #include <pcl/point_types.h>
00049 #include <pcl/point_cloud.h>
00050 #include <pcl/ros/conversions.h>
00051 #include <pcl_ros/transforms.h>
00052 
00053 #include <actionlib/server/simple_action_server.h>
00054 #include <actionlib/client/simple_action_client.h>
00055 #include <actionlib/client/simple_client_goal_state.h>
00056 
00057 #include <pr2_controllers_msgs/PointHeadAction.h>
00058 #include <control_msgs/FollowJointTrajectoryAction.h>
00059 
00060 #include <head_monitor_msgs/HeadMonitorStatus.h>
00061 #include <head_monitor_msgs/HeadMonitorAction.h>
00062 #include <head_monitor_msgs/PreplanHeadScanAction.h>
00063 
00064 #include <visualization_msgs/MarkerArray.h>
00065 #include <visualization_msgs/Marker.h>
00066 
00067 #include <tf/transform_listener.h>
00068 
00069 static const std::string RIGHT_ARM_GROUP = "right_arm";
00070 static const std::string LEFT_ARM_GROUP = "left_arm";
00071 
00072 static const double JOINT_BOUNDS_MARGIN = .02;
00073 
00074 std::string convertFromGroupNameToArmName(const std::string& arm_name) {
00075   if(arm_name.find(RIGHT_ARM_GROUP) != std::string::npos) {
00076     return(RIGHT_ARM_GROUP);
00077   } else if(arm_name.find(LEFT_ARM_GROUP) != std::string::npos) {
00078     return(LEFT_ARM_GROUP);
00079   } else {
00080     ROS_WARN_STREAM("Neither left arm group or right arm group in group: " << arm_name);
00081   }
00082   return std::string("");
00083 }
00084 
00085 class HeadMonitor
00086 {
00087 protected:
00088 
00089   ros::NodeHandle private_handle_;
00090   ros::NodeHandle root_handle_;
00091   actionlib::SimpleActionServer<head_monitor_msgs::HeadMonitorAction> head_monitor_action_server_;
00092   actionlib::SimpleActionServer<head_monitor_msgs::PreplanHeadScanAction> head_preplan_scan_action_server_;
00093 
00094   ros::Publisher marker_pub_;
00095 
00096   actionlib::SimpleActionClient<control_msgs::FollowJointTrajectoryAction> head_controller_action_client_;
00097   actionlib::SimpleActionClient<control_msgs::FollowJointTrajectoryAction>* right_arm_controller_action_client_;
00098   actionlib::SimpleActionClient<control_msgs::FollowJointTrajectoryAction>* left_arm_controller_action_client_;
00099   actionlib::SimpleActionClient<pr2_controllers_msgs::PointHeadAction> point_head_action_client_;
00100 
00101   std::string current_group_name_;
00102   actionlib::SimpleActionClient<control_msgs::FollowJointTrajectoryAction>* current_arm_controller_action_client_;
00103 
00104   bool use_left_arm_;
00105   bool use_right_arm_;
00106 
00107   planning_environment::CollisionModelsInterface* collision_models_interface_;
00108   planning_environment::KinematicModelStateMonitor* kmsm_;
00109 
00110   head_monitor_msgs::HeadMonitorGoal monitor_goal_;
00111   head_monitor_msgs::HeadMonitorFeedback monitor_feedback_;
00112   head_monitor_msgs::HeadMonitorResult monitor_result_;
00113 
00114   sensor_msgs::JointState last_joint_state_;
00115 
00116   trajectory_msgs::JointTrajectory logged_trajectory_;
00117   ros::Time logged_trajectory_start_time_;
00118 
00119   tf::TransformListener tf_;
00120 
00121   ros::Timer paused_callback_timer_;
00122   ros::Timer start_trajectory_timer_;
00123 
00124   visualization_msgs::Marker marker_;
00125 
00126   tf::MessageFilter<sensor_msgs::PointCloud2> *mn_;
00127   message_filters::Subscriber<sensor_msgs::PointCloud2> *sub_;
00128 
00129   //TODO - get rid of once we have Adam's stuff
00130   double start_head_pan_, start_head_tilt_, goal_head_pan_, goal_head_tilt_;
00131 
00132   double point_sphere_size_;
00133   double pause_time_;
00134   double max_point_distance_;
00135 
00136   bool do_monitoring_;
00137   bool do_preplan_scan_;
00138 
00139   head_monitor_msgs::HeadMonitorStatus current_execution_status_;
00140 
00141 public:
00142 
00143   HeadMonitor() :
00144     private_handle_("~"),
00145     head_monitor_action_server_(root_handle_, "head_monitor_action", false),
00146     head_preplan_scan_action_server_(root_handle_, "preplan_head_scan", boost::bind(&HeadMonitor::preplanHeadScanCallback, this, _1), false), 
00147     head_controller_action_client_("/head_traj_controller/follow_joint_trajectory", true),
00148     point_head_action_client_("/head_traj_controller/point_head_action", true)
00149   {
00150     current_execution_status_.status = current_execution_status_.IDLE;
00151 
00152     private_handle_.param<double>("point_sphere_size", point_sphere_size_, .01);
00153     private_handle_.param<double>("pause_time", pause_time_, 5.0);
00154     private_handle_.param<double>("max_point_distance", max_point_distance_, 1.0);
00155     private_handle_.param<bool>("do_preplan_scan", do_preplan_scan_, true);
00156     private_handle_.param<bool>("do_monitoring", do_monitoring_, true);
00157     private_handle_.param<bool>("use_left_arm", use_left_arm_, true);
00158     private_handle_.param<bool>("use_right_arm", use_right_arm_, true);
00159 
00160     std::string robot_description_name = root_handle_.resolveName("robot_description", true);
00161     
00162     collision_models_interface_ = new planning_environment::CollisionModelsInterface(robot_description_name);
00163     kmsm_ = new planning_environment::KinematicModelStateMonitor(collision_models_interface_, &tf_);
00164 
00165     kmsm_->addOnStateUpdateCallback(boost::bind(&HeadMonitor::jointStateCallback, this, _1));
00166 
00167     if(do_preplan_scan_ && do_monitoring_) {
00168       sub_ = new message_filters::Subscriber<sensor_msgs::PointCloud2> (root_handle_, "cloud_in", 1);   
00169       mn_ = new tf::MessageFilter<sensor_msgs::PointCloud2> (*sub_, tf_, "", 1);
00170       mn_->setTargetFrame(collision_models_interface_->getWorldFrameId());
00171       mn_->registerCallback(boost::bind(&HeadMonitor::cloudCallback, this, _1));
00172     }
00173 
00174     head_monitor_action_server_.registerGoalCallback(boost::bind(&HeadMonitor::monitorGoalCallback, this));
00175     head_monitor_action_server_.registerPreemptCallback(boost::bind(&HeadMonitor::monitorPreemptCallback, this));
00176 
00177     if(use_right_arm_) {
00178       right_arm_controller_action_client_ = new actionlib::SimpleActionClient<control_msgs::FollowJointTrajectoryAction>("/r_arm_controller/follow_joint_trajectory", true);
00179       while(ros::ok() && !right_arm_controller_action_client_->waitForServer(ros::Duration(1.0))){
00180         ROS_INFO("Waiting for the right joint_trajectory_action server to come up.");
00181       }
00182     }
00183     if(use_left_arm_) {
00184       left_arm_controller_action_client_ = new actionlib::SimpleActionClient<control_msgs::FollowJointTrajectoryAction>("/l_arm_controller/follow_joint_trajectory", true);
00185       while(ros::ok() && !left_arm_controller_action_client_->waitForServer(ros::Duration(1.0))){
00186         ROS_INFO("Waiting for the left joint_trajectory_action server to come up.");
00187       }
00188     }
00189 
00190     if(!use_left_arm_ && !use_right_arm_) {
00191       ROS_ERROR_STREAM("No arms specified.  Exiting");
00192       exit(0);
00193     }
00194 
00195     ROS_INFO("Connected to the controllers");
00196     
00197     head_monitor_action_server_.start();
00198     head_preplan_scan_action_server_.start();
00199         
00200     ROS_INFO_STREAM("Starting head monitor action server for "<<ros::this_node::getName());
00201   }
00202 
00203   ~HeadMonitor(void)
00204   {
00205     delete kmsm_;
00206     delete collision_models_interface_;
00207     delete right_arm_controller_action_client_;
00208     delete left_arm_controller_action_client_;
00209   }
00210 
00214   
00215   void cloudCallback (const sensor_msgs::PointCloud2ConstPtr &cloud2)
00216   {
00217     if(current_execution_status_.status == current_execution_status_.IDLE ||
00218        current_execution_status_.status == current_execution_status_.PREPLAN_SCAN) {
00219       return;
00220     }
00221 
00222     ros::Time callback_delay = ros::Time::now();
00223 
00224     pcl::PointCloud<pcl::PointXYZ> pcl_cloud, trans_cloud, near_cloud;
00225     pcl::fromROSMsg(*cloud2, pcl_cloud);
00226 
00227     if(pcl_cloud.points.size() == 0) {
00228       ROS_WARN_STREAM("No points in cloud");
00229       return;
00230     } 
00231 
00232     collision_models_interface_->bodiesLock();
00233 
00234     sensor_msgs::JointState js = last_joint_state_;
00235     trajectory_msgs::JointTrajectory joint_trajectory_subset;
00236     if(current_execution_status_.status == current_execution_status_.EXECUTING) {
00237       planning_environment::removeCompletedTrajectory(collision_models_interface_->getParsedDescription(),
00238                                                       monitor_goal_.joint_trajectory,
00239                                                       js,
00240                                                       joint_trajectory_subset,
00241                                                       false);
00242     } else {
00243       joint_trajectory_subset = monitor_goal_.joint_trajectory;
00244     }
00245 
00246     if(joint_trajectory_subset.points.size() == 0) {
00247       //no points left to check 
00248       if(current_execution_status_.status == current_execution_status_.PAUSED) {
00249         ROS_ERROR_STREAM("Paused, but closest trajectory point is goal");
00250       }
00251       collision_models_interface_->bodiesUnlock();
00252       return;
00253     }
00254     ros::Time n1 = ros::Time::now();
00255 
00256     planning_models::KinematicState state(collision_models_interface_->getKinematicModel());
00257     kmsm_->setStateValuesFromCurrentValues(state);
00258 
00259     planning_environment::updateAttachedObjectBodyPoses(collision_models_interface_,
00260                                                         state,
00261                                                         tf_);
00262 
00263     //now in the right frame
00264 
00265     if (collision_models_interface_->getWorldFrameId() != pcl_cloud.header.frame_id) {
00266       pcl_ros::transformPointCloud(collision_models_interface_->getWorldFrameId(), pcl_cloud, trans_cloud, tf_);
00267     } else {
00268       trans_cloud = pcl_cloud;
00269     }
00270 
00271     tf::Transform cur_link_pose = state.getLinkState(monitor_goal_.target_link)->getGlobalCollisionBodyTransform();
00272     near_cloud.header = trans_cloud.header;
00273     for(unsigned int i = 0; i < trans_cloud.points.size(); i++) {
00274       tf::Vector3 pt = tf::Vector3(trans_cloud.points[i].x, trans_cloud.points[i].y, trans_cloud.points[i].z);
00275       double dist = pt.distance(cur_link_pose.getOrigin());
00276       if(dist <= max_point_distance_) {
00277         near_cloud.push_back(trans_cloud.points[i]);
00278       }
00279     }
00280     
00281     std::vector<shapes::Shape*> spheres(near_cloud.points.size());;
00282     std::vector<tf::Transform> positions(near_cloud.points.size());
00283     
00284     ros::Time n3 = ros::Time::now();
00285       
00286     if(near_cloud.points.size() != 0) {
00287 
00288       tf::Quaternion ident(0.0, 0.0, 0.0, 1.0);
00289       //making spheres from the points
00290       for (unsigned int i = 0 ; i < near_cloud.points.size(); ++i) {
00291         positions[i] = tf::Transform(ident, 
00292                                    tf::Vector3(near_cloud.points[i].x, near_cloud.points[i].y, near_cloud.points[i].z));
00293         spheres[i] = new shapes::Sphere(point_sphere_size_);
00294       }
00295       
00296       //collisions should have been turned off with everything but this
00297       collision_models_interface_->addStaticObject("point_spheres",
00298                                                    spheres,
00299                                                    positions,
00300                                                    0.0);
00301 
00302       //turning off collisions except between point spheres and downstream links
00303       collision_space::EnvironmentModel::AllowedCollisionMatrix acm = collision_models_interface_->getCollisionSpace()->getCurrentAllowedCollisionMatrix();
00304       const planning_models::KinematicModel::JointModelGroup* joint_model_group = collision_models_interface_->getKinematicModel()->getModelGroup(current_group_name_);
00305       
00306       acm.addEntry("point_spheres", true);
00307       acm.changeEntry(true);
00308       acm.changeEntry("point_spheres", joint_model_group->getUpdatedLinkModelNames(), false);
00309 
00310       collision_models_interface_->setAlteredAllowedCollisionMatrix(acm);
00311       
00312     } else {
00313       //turning off all collisions
00314       collision_space::EnvironmentModel::AllowedCollisionMatrix acm = collision_models_interface_->getCollisionSpace()->getCurrentAllowedCollisionMatrix();
00315       acm.changeEntry(true);
00316 
00317       collision_models_interface_->setAlteredAllowedCollisionMatrix(acm);
00318     }
00319     arm_navigation_msgs::Constraints empty_constraints;
00320     arm_navigation_msgs::ArmNavigationErrorCodes error_code;
00321     std::vector<arm_navigation_msgs::ArmNavigationErrorCodes> trajectory_error_codes;
00322     
00323     ros::Time n2 = ros::Time::now();
00324     if(!collision_models_interface_->isJointTrajectoryValid(state, 
00325                                                             joint_trajectory_subset,
00326                                                             empty_constraints,
00327                                                             empty_constraints, 
00328                                                             error_code,
00329                                                             trajectory_error_codes, 
00330                                                             false)) {
00331       ROS_INFO_STREAM("Validity check took " << (ros::Time::now()-n2).toSec());
00332       ROS_INFO_STREAM("Trajectory check took " << (ros::Time::now() - n1).toSec() 
00333                        << " shape " << (n2-n3).toSec()
00334                        << " traj part " << (ros::Time::now() - n2).toSec());
00335       if(current_execution_status_.status == current_execution_status_.MONITOR_BEFORE_EXECUTION ||
00336          current_execution_status_.status == current_execution_status_.EXECUTING) {
00337         ROS_WARN_STREAM("Trajectory judged invalid " << error_code.val << ". Pausing");
00338         //TODO - stop more gracefully, do something else?
00339         if(current_execution_status_.status == current_execution_status_.MONITOR_BEFORE_EXECUTION) {
00340           start_trajectory_timer_.stop();
00341         } else {
00342           current_arm_controller_action_client_->cancelGoal();
00343           ROS_INFO_STREAM("Delay from data timestamp to cancel is " << (ros::Time::now() - cloud2->header.stamp).toSec()
00344                           << " delay to receipt is " << (callback_delay - cloud2->header.stamp).toSec());
00345           
00346         }
00347         stopHead();
00348         current_execution_status_.status = current_execution_status_.PAUSED;
00349         kmsm_->setStateValuesFromCurrentValues(state);
00350         planning_environment::convertKinematicStateToRobotState(state,
00351                                                                 ros::Time::now(),
00352                                                                 collision_models_interface_->getWorldFrameId(),
00353                                                                 monitor_feedback_.current_state);
00354         unsigned int trajectory_point = trajectory_error_codes.size();
00355         if(trajectory_error_codes.size() > 0) {
00356           trajectory_point--;
00357         }
00358         ROS_INFO_STREAM("Setting trajectory state to point " << trajectory_point << " of " << joint_trajectory_subset.points.size());
00359         
00360         std::map<std::string, double> vals;
00361         for(unsigned int i = 0; i < joint_trajectory_subset.joint_names.size(); i++) {
00362           vals[joint_trajectory_subset.joint_names[i]] = joint_trajectory_subset.points[trajectory_point].positions[i];
00363         }
00364         state.setKinematicState(vals);
00365         planning_environment::convertKinematicStateToRobotState(state,
00366                                                                 ros::Time::now(),
00367                                                                 collision_models_interface_->getWorldFrameId(),
00368                                                                 monitor_feedback_.paused_trajectory_state);
00369         monitor_feedback_.paused_collision_map.header.frame_id = collision_models_interface_->getWorldFrameId();
00370         monitor_feedback_.paused_collision_map.header.stamp = cloud2->header.stamp;
00371         monitor_feedback_.paused_collision_map.id = "point_spheres";
00372         monitor_feedback_.paused_collision_map.operation.operation = arm_navigation_msgs::CollisionObjectOperation::ADD;
00373         for (unsigned int j = 0 ; j < spheres.size(); ++j) {
00374           arm_navigation_msgs::Shape obj;
00375           if (planning_environment::constructObjectMsg(spheres[j], obj)) {
00376             geometry_msgs::Pose pose;
00377             tf::poseTFToMsg(positions[j], pose);
00378             monitor_feedback_.paused_collision_map.shapes.push_back(obj);
00379             monitor_feedback_.paused_collision_map.poses.push_back(pose);
00380           }
00381         }
00382         std::vector<arm_navigation_msgs::ContactInformation> contacts;
00383         collision_models_interface_->getAllCollisionsForState(state, contacts, 1);
00384         if(contacts.size() == 0) {
00385           ROS_INFO_STREAM("No contacts for last trajectory state");
00386         } else {
00387           for(unsigned int i = 0; i < contacts.size(); i++) {
00388             ROS_INFO_STREAM("Contact between " << contacts[i].contact_body_1 << " and " << contacts[i].contact_body_2
00389                             << " at point " << contacts[i].position.x << " " << contacts[i].position.y << " " << contacts[i].position.z);
00390           }
00391           
00392         }
00393         head_monitor_action_server_.publishFeedback(monitor_feedback_);        
00394         paused_callback_timer_ = root_handle_.createTimer(ros::Duration(pause_time_), boost::bind(&HeadMonitor::pauseTimeoutCallback, this), true);
00395       } 
00396       //if paused no need to do anything else, except maybe provide additional feedback?
00397     } else {
00398       if(current_execution_status_.status == current_execution_status_.PAUSED) {
00399         paused_callback_timer_.stop();
00400        
00401         ROS_WARN_STREAM("Unpausing");
00402 
00403         current_execution_status_.status = current_execution_status_.MONITOR_BEFORE_EXECUTION;
00404         
00405         sensor_msgs::JointState js = last_joint_state_;
00406         trajectory_msgs::JointTrajectory joint_trajectory_subset;
00407         
00408         planning_environment::removeCompletedTrajectory(collision_models_interface_->getParsedDescription(),
00409                                                         monitor_goal_.joint_trajectory,
00410                                                         js,
00411                                                         joint_trajectory_subset,
00412                                                         false);
00413 
00414         control_msgs::FollowJointTrajectoryGoal goal;
00415         goal.trajectory = generateHeadTrajectory(monitor_goal_.target_link, joint_trajectory_subset);
00416         head_controller_action_client_.sendGoal(goal);
00417 
00418         //Setting timer for actually sending trajectory
00419         start_trajectory_timer_ = root_handle_.createTimer(ros::Duration(monitor_goal_.time_offset), boost::bind(&HeadMonitor::trajectoryTimerCallback, this), true);
00420       }
00421     }
00422     if(near_cloud.points.size() != 0) {
00423       collision_models_interface_->deleteStaticObject("point_spheres");
00424       monitor_feedback_.paused_collision_map.shapes.clear();
00425       monitor_feedback_.paused_collision_map.poses.clear();
00426     }
00427     ROS_DEBUG_STREAM("Trajectory check took " << (ros::Time::now() - n1).toSec() 
00428                     << " shape " << (n2-n3).toSec()
00429                     << " traj part " << (ros::Time::now() - n2).toSec());
00430     collision_models_interface_->bodiesUnlock();
00431   }
00432   
00433   void moveInsideSafetyLimits(const head_monitor_msgs::PreplanHeadScanGoalConstPtr &goal,
00434                               const planning_models::KinematicState& state) {
00435     const planning_models::KinematicModel::JointModelGroup* joint_model_group = collision_models_interface_->getKinematicModel()->getModelGroup(goal->group_name);
00436     const std::vector<std::string>& joint_names = joint_model_group->getJointModelNames();
00437     ROS_DEBUG_STREAM("Group name " << goal->group_name);
00438 
00439     if(goal->group_name == RIGHT_ARM_GROUP && !use_right_arm_) {
00440       ROS_WARN_STREAM("Not configured for use with group name " << RIGHT_ARM_GROUP);
00441       return;
00442     }
00443     if(goal->group_name == LEFT_ARM_GROUP && !use_left_arm_) {
00444       ROS_WARN_STREAM("Not configured for use with group name " << LEFT_ARM_GROUP);
00445       return;
00446     }
00447 
00448     if(state.areJointsWithinBounds(joint_names)) {
00449       return;
00450     }
00451     trajectory_msgs::JointTrajectory traj;
00452     traj.joint_names = joint_names;
00453     traj.header.stamp = ros::Time::now();
00454     traj.header.frame_id = collision_models_interface_->getWorldFrameId();
00455     traj.points.resize(1);
00456     traj.points[0].positions.resize(joint_names.size());
00457     traj.points[0].velocities.resize(joint_names.size());
00458     traj.points[0].time_from_start = ros::Duration(.4);
00459 
00460     std::map<std::string, double> joint_values;
00461     state.getKinematicStateValues(joint_values);
00462     
00463     for(unsigned int j = 0; j < joint_names.size(); j++) {
00464       if(!state.isJointWithinBounds(joint_names[j])) {
00465         std::pair<double, double> bounds; 
00466         state.getJointState(joint_names[j])->getJointModel()->getVariableBounds(joint_names[j], bounds);
00467         ROS_INFO_STREAM("Joint " << joint_names[j] << " out of bounds. " <<
00468                         " value: " << state.getJointState(joint_names[j])->getJointStateValues()[0] << 
00469                         " low: " << bounds.first << " high: " << bounds.second);
00470         if(joint_values[joint_names[j]] < bounds.first) {
00471           traj.points[0].positions[j] = bounds.first+JOINT_BOUNDS_MARGIN;
00472           ROS_INFO_STREAM("Setting joint " << joint_names[j] << " inside lower bound " << traj.points[0].positions[j]);
00473         } else {
00474           traj.points[0].positions[j] = bounds.second-JOINT_BOUNDS_MARGIN;
00475           ROS_INFO_STREAM("Setting joint " << joint_names[j] << " inside upper bound " << traj.points[0].positions[j]);
00476         }
00477       } else {
00478         traj.points[0].positions[j] = joint_values[joint_names[j]];
00479       }
00480     }
00481 
00482     control_msgs::FollowJointTrajectoryGoal traj_goal;  
00483     traj_goal.trajectory = traj;
00484 
00485     current_arm_controller_action_client_ = ((goal->group_name == RIGHT_ARM_GROUP) ? right_arm_controller_action_client_ : left_arm_controller_action_client_);
00486 
00487     if(current_arm_controller_action_client_->sendGoalAndWait(traj_goal, ros::Duration(1.0), ros::Duration(.5)) != actionlib::SimpleClientGoalState::SUCCEEDED) {
00488       ROS_WARN_STREAM("Joint bounds correction trajectory failed");
00489     }
00490   }
00491 
00492   void preplanHeadScanCallback(const head_monitor_msgs::PreplanHeadScanGoalConstPtr &goal)
00493   { 
00494     head_monitor_msgs::PreplanHeadScanResult res;
00495 
00496     collision_models_interface_->bodiesLock();
00497 
00498     if(current_execution_status_.status != current_execution_status_.IDLE) {
00499       ROS_WARN_STREAM("Got preplan in something other than IDLE mode");
00500     }
00501 
00502     //need a kinematic state
00503     planning_models::KinematicState state(collision_models_interface_->getKinematicModel());
00504     
00505     kmsm_->setStateValuesFromCurrentValues(state);
00506 
00507     moveInsideSafetyLimits(goal, state);
00508 
00509     if(!do_preplan_scan_) {
00510       collision_models_interface_->bodiesUnlock();
00511       head_preplan_scan_action_server_.setSucceeded(res);
00512       return;
00513     }
00514 
00515     current_execution_status_.status = current_execution_status_.PREPLAN_SCAN;
00516 
00517     kmsm_->setStateValuesFromCurrentValues(state);
00518 
00519     //supplementing with start state changes
00520     planning_environment::setRobotStateAndComputeTransforms(goal->motion_plan_request.start_state,
00521                                                             state);
00522     double x_start, y_start, z_start;
00523 
00524     if(!state.hasLinkState(goal->head_monitor_link)) {
00525       ROS_WARN_STREAM("No monitor link " << goal->head_monitor_link);
00526       head_preplan_scan_action_server_.setAborted(res);
00527       current_execution_status_.status = current_execution_status_.IDLE;
00528       collision_models_interface_->bodiesUnlock();
00529       return;
00530     }
00531 
00532     tf::Transform link_state = state.getLinkState(goal->head_monitor_link)->getGlobalCollisionBodyTransform();
00533     x_start = link_state.getOrigin().x();
00534     y_start = link_state.getOrigin().y();
00535     z_start = link_state.getOrigin().z();
00536 
00537     double x_goal, y_goal, z_goal;
00538     if(goal->motion_plan_request.goal_constraints.position_constraints.size() >= 1
00539        && goal->motion_plan_request.goal_constraints.orientation_constraints.size() >= 1) {
00540       geometry_msgs::PoseStamped goal_pose 
00541         = arm_navigation_msgs::poseConstraintsToPoseStamped(goal->motion_plan_request.goal_constraints.position_constraints[0],
00542                                                              goal->motion_plan_request.goal_constraints.orientation_constraints[0]);
00543 
00544       std::string es;
00545       if (tf_.getLatestCommonTime(collision_models_interface_->getWorldFrameId(), goal_pose.header.frame_id, goal_pose.header.stamp, &es) != tf::NO_ERROR) {
00546       }
00547       geometry_msgs::PoseStamped psout;
00548       tf_.transformPose(collision_models_interface_->getWorldFrameId(), goal_pose, psout);
00549 
00550       x_goal = psout.pose.position.x;
00551       y_goal = psout.pose.position.y;
00552       z_goal = psout.pose.position.z;
00553     } else {
00554       if(goal->motion_plan_request.goal_constraints.joint_constraints.size() <= 1) {
00555         ROS_WARN("Not a pose goal and not enough joint constraints");
00556         head_preplan_scan_action_server_.setAborted(res);
00557         current_execution_status_.status = current_execution_status_.IDLE;
00558         collision_models_interface_->bodiesUnlock();
00559         return;
00560       }
00561       std::map<std::string, double> joint_values;
00562       for(unsigned int i = 0; i < goal->motion_plan_request.goal_constraints.joint_constraints.size(); i++) {
00563         joint_values[goal->motion_plan_request.goal_constraints.joint_constraints[i].joint_name] = goal->motion_plan_request.goal_constraints.joint_constraints[i].position;
00564       }
00565       state.setKinematicState(joint_values);
00566       tf::Transform link_state = state.getLinkState(goal->head_monitor_link)->getGlobalCollisionBodyTransform();
00567       x_goal = link_state.getOrigin().x();
00568       y_goal = link_state.getOrigin().y();
00569       z_goal = link_state.getOrigin().z();
00570     }
00571     std::map<std::string, double> state_values;
00572     ROS_INFO_STREAM("Looking at goal " << x_goal << " " << y_goal << " " << z_goal);
00573     lookAt(collision_models_interface_->getWorldFrameId(), x_goal, y_goal, z_goal, true);
00574     kmsm_->setStateValuesFromCurrentValues(state);
00575     state.getKinematicStateValues(state_values);
00576     goal_head_pan_ = state_values["head_pan_joint"];
00577     goal_head_tilt_ = state_values["head_tilt_joint"];
00578     ROS_INFO_STREAM("Looking at start " << x_start << " " << y_start << " " << z_start);
00579     lookAt(collision_models_interface_->getWorldFrameId(), x_start, y_start, z_start, true);
00580     kmsm_->setStateValuesFromCurrentValues(state);
00581     state.getKinematicStateValues(state_values);
00582     start_head_pan_ = state_values["head_pan_joint"];
00583     start_head_tilt_ = state_values["head_tilt_joint"];
00584     head_preplan_scan_action_server_.setSucceeded(res);
00585     current_execution_status_.status = current_execution_status_.IDLE;
00586     collision_models_interface_->bodiesUnlock();
00587   }
00588 
00589   // Called when a new monitoring goal is received
00590   void monitorGoalCallback()
00591   {
00592     if(current_execution_status_.status == current_execution_status_.MONITOR_BEFORE_EXECUTION &&
00593        current_execution_status_.status == current_execution_status_.EXECUTING &&
00594        current_execution_status_.status == current_execution_status_.PAUSED) {
00595       ROS_WARN_STREAM("Got new goal while executing");
00596       stopEverything();
00597     }
00598 
00599     if(!head_monitor_action_server_.isNewGoalAvailable())
00600     {
00601       ROS_INFO_STREAM("Preempted, no new goal");
00602       return;
00603     }
00604     monitor_goal_ = head_monitor_msgs::HeadMonitorGoal(*head_monitor_action_server_.acceptNewGoal());
00605     current_group_name_ = convertFromGroupNameToArmName(monitor_goal_.group_name);
00606 
00607     if(current_group_name_ == RIGHT_ARM_GROUP && !use_right_arm_) {
00608       ROS_WARN_STREAM("Not configured for use with group name " << RIGHT_ARM_GROUP);
00609       monitor_result_.error_code.val = monitor_result_.error_code.INVALID_GROUP_NAME;
00610       head_monitor_action_server_.setAborted(monitor_result_);
00611       return;
00612     }
00613     if(current_group_name_ == LEFT_ARM_GROUP && !use_left_arm_) {
00614       ROS_WARN_STREAM("Not configured for use with group name " << LEFT_ARM_GROUP);
00615       monitor_result_.error_code.val = monitor_result_.error_code.INVALID_GROUP_NAME;
00616       head_monitor_action_server_.setAborted(monitor_result_);
00617       return;
00618     }
00619 
00620     if(current_group_name_.empty()) {
00621       ROS_WARN_STREAM("Group name doesn't have left or right arm in it, gonna be bad");
00622     }
00623 
00624     current_arm_controller_action_client_ = ((current_group_name_ == RIGHT_ARM_GROUP) ? right_arm_controller_action_client_ : left_arm_controller_action_client_);
00625 
00626     logged_trajectory_ = monitor_goal_.joint_trajectory;
00627     logged_trajectory_.points.clear();
00628 
00629     logged_trajectory_start_time_ = ros::Time::now();
00630 
00631     if(do_preplan_scan_ && do_monitoring_) {
00632       current_execution_status_.status = current_execution_status_.MONITOR_BEFORE_EXECUTION;
00633       
00634       //Generating head trajectory and deploying it
00635       
00636       control_msgs::FollowJointTrajectoryGoal goal;
00637       goal.trajectory = generateHeadTrajectory(monitor_goal_.target_link, monitor_goal_.joint_trajectory);
00638       head_controller_action_client_.sendGoal(goal);
00639       //Setting timer for actually sending trajectory
00640       start_trajectory_timer_ = root_handle_.createTimer(ros::Duration(monitor_goal_.time_offset), boost::bind(&HeadMonitor::trajectoryTimerCallback, this), true);
00641     } else {
00642       //calling this directly
00643       trajectoryTimerCallback();
00644     }
00645   }
00646 
00647   void stopHead()
00648   {
00649     head_controller_action_client_.cancelAllGoals();
00650   }
00651   
00652   void stopArm() 
00653   {
00654     if(current_execution_status_.status == current_execution_status_.EXECUTING) {
00655       current_arm_controller_action_client_->cancelGoal();
00656     }
00657   }
00658 
00659   void stopEverything() {
00660     start_trajectory_timer_.stop();
00661     paused_callback_timer_.stop();
00662     stopHead();
00663     stopArm();
00664   }
00665 
00666   void monitorPreemptCallback()
00667   {
00668     if(current_execution_status_.status != current_execution_status_.MONITOR_BEFORE_EXECUTION &&
00669        current_execution_status_.status != current_execution_status_.EXECUTING &&
00670        current_execution_status_.status != current_execution_status_.PAUSED) {
00671       ROS_WARN_STREAM("Got preempt not in a relevant mode");
00672       return;
00673     }
00674     //no reason not to cancel
00675     stopEverything();
00676 
00677     current_execution_status_.status = current_execution_status_.IDLE;
00678 
00679     ROS_INFO_STREAM(ros::this_node::getName() << ": Preempted");
00680     head_monitor_action_server_.setPreempted(monitor_result_);
00681   }
00682 
00683   void jointStateCallback(const sensor_msgs::JointStateConstPtr& joint_state) {
00684     last_joint_state_ = *joint_state;
00685     if(current_execution_status_.status == current_execution_status_.IDLE
00686        || current_execution_status_.status == current_execution_status_.PREPLAN_SCAN) {
00687       return;
00688     }
00689     std::map<std::string, double> joint_state_map;
00690     std::map<std::string, double> joint_velocity_map;
00691     //message already been validated in kmsm
00692     for (unsigned int i = 0 ; i < joint_state->position.size(); ++i)
00693     {
00694       joint_state_map[joint_state->name[i]] = joint_state->position[i];
00695       joint_velocity_map[joint_state->name[i]] = joint_state->velocity[i];
00696     }
00697     trajectory_msgs::JointTrajectoryPoint point;
00698     point.positions.resize(logged_trajectory_.joint_names.size());
00699     point.velocities.resize(logged_trajectory_.joint_names.size());
00700     for(unsigned int i = 0; i < logged_trajectory_.joint_names.size(); i++) {
00701       point.positions[i] = joint_state_map[logged_trajectory_.joint_names[i]];
00702       point.velocities[i] = joint_velocity_map[logged_trajectory_.joint_names[i]];
00703     }
00704     point.time_from_start = ros::Time::now()-logged_trajectory_start_time_;
00705     logged_trajectory_.points.push_back(point);
00706   }
00707 
00708   void controllerDoneCallback(const actionlib::SimpleClientGoalState& state,
00709                               const control_msgs::FollowJointTrajectoryResultConstPtr& result)
00710   {
00711     if(current_execution_status_.status != current_execution_status_.EXECUTING) {
00712       //because we cancelled
00713       return;
00714     }
00715     ROS_INFO_STREAM("Trajectory reported done with state " << state.toString());
00716     current_execution_status_.status = current_execution_status_.IDLE;
00717     monitor_result_.actual_trajectory = logged_trajectory_;
00718     monitor_result_.error_code.val = monitor_result_.error_code.SUCCESS;
00719     head_monitor_action_server_.setSucceeded(monitor_result_);
00720   }
00721 
00722   void pauseTimeoutCallback() {
00723     ROS_INFO_STREAM("Paused trajectory timed out");
00724     stopEverything();
00725     current_execution_status_.status = current_execution_status_.IDLE;
00726     monitor_result_.actual_trajectory = logged_trajectory_;
00727     monitor_result_.error_code.val = monitor_result_.error_code.TIMED_OUT;
00728     head_monitor_action_server_.setAborted(monitor_result_);
00729   }
00730 
00734 
00735 
00736   void trajectoryTimerCallback() {
00737     current_execution_status_.status = current_execution_status_.EXECUTING;
00738 
00739     control_msgs::FollowJointTrajectoryGoal goal;  
00740 
00741     sensor_msgs::JointState js = last_joint_state_;
00742     planning_environment::removeCompletedTrajectory(collision_models_interface_->getParsedDescription(),
00743                                                     monitor_goal_.joint_trajectory,
00744                                                     js,
00745                                                     goal.trajectory,
00746                                                     false);
00747     goal.trajectory.header.stamp = ros::Time::now()+ros::Duration(0.2);
00748 
00749     ROS_INFO("Sending trajectory with %d points (excerpted from %d points) and timestamp: %f",(int)goal.trajectory.points.size(),(int) monitor_goal_.joint_trajectory.points.size(), goal.trajectory.header.stamp.toSec());
00750     current_arm_controller_action_client_->sendGoal(goal,boost::bind(&HeadMonitor::controllerDoneCallback, this, _1, _2));
00751   }
00752 
00756 
00757   trajectory_msgs::JointTrajectory generateHeadTrajectory(const std::string& link, const trajectory_msgs::JointTrajectory& joint_trajectory) {
00758     trajectory_msgs::JointTrajectory ret_traj;
00759     ret_traj.header = joint_trajectory.header;
00760     ret_traj.header.stamp = ros::Time::now();
00761     ret_traj.joint_names.resize(2); 
00762     ret_traj.joint_names[0] = "head_pan_joint";
00763     ret_traj.joint_names[1] = "head_tilt_joint";
00764 
00765     //TODO - incorporate Adam's stuff
00766     
00767     ret_traj.points.resize(2);
00768 
00769     ret_traj.points[0].positions.resize(2);
00770     ret_traj.points[1].positions.resize(2);
00771     
00772     ret_traj.points[0].positions[0] = start_head_pan_;
00773     ret_traj.points[0].positions[1] = start_head_tilt_;
00774     ret_traj.points[0].time_from_start = ros::Duration(.2);
00775 
00776     ret_traj.points[1].positions[0] = goal_head_pan_;
00777     ret_traj.points[1].positions[1] = goal_head_tilt_;
00778     ret_traj.points[1].time_from_start = joint_trajectory.points.back().time_from_start;
00779 
00780     return ret_traj;
00781   }
00782 
00783  // Points the head at a point in a given frame  
00784   void lookAt(std::string frame_id, double x, double y, double z, bool wait)
00785   {
00786     
00787     pr2_controllers_msgs::PointHeadGoal goal;
00788 
00789     //the target point, expressed in the requested frame
00790     geometry_msgs::PointStamped point;
00791     point.header.frame_id = frame_id;
00792     point.point.x = x; 
00793     point.point.y = y; 
00794     point.point.z = z;
00795   
00796     goal.target = point;
00797   
00798     //take at least 0.4 seconds to get there, lower value makes head jerky
00799     goal.min_duration = ros::Duration(.4);
00800     goal.max_velocity = 0.4;
00801 
00802     if(wait)
00803     {
00804       if(point_head_action_client_.sendGoalAndWait(goal, ros::Duration(15.0), ros::Duration(0.5)) != actionlib::SimpleClientGoalState::SUCCEEDED)
00805         ROS_WARN("Point head timed out, continuing");
00806     }
00807     else
00808     {
00809       point_head_action_client_.sendGoal(goal);
00810     }
00811   }
00812 };
00813 
00814 
00815 int main(int argc, char** argv)
00816 {
00817   ros::init(argc, argv, "move_arm_head_monitor");
00818 
00819   ros::AsyncSpinner spinner(3); 
00820   spinner.start();
00821 
00822   HeadMonitor head_monitor;
00823 
00824   ros::waitForShutdown();
00825   return 0;
00826 }
00827 


move_arm_head_monitor
Author(s): Adam Harmat
autogenerated on Fri Dec 6 2013 21:09:57