$search
00001 /********************************************************************* 00002 * 00003 * Software License Agreement (BSD License) 00004 * 00005 * Copyright (c) 2008, 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 Sachin Chitta, Ioan Sucan 00036 *********************************************************************/ 00037 00038 #include <ros/ros.h> 00039 00040 #include <tf/tf.h> 00041 #include <tf/transform_listener.h> 00042 #include <urdf/model.h> 00043 #include <angles/angles.h> 00044 00045 #include <actionlib/client/action_client.h> 00046 #include <control_msgs/FollowJointTrajectoryAction.h> 00047 00048 #include <actionlib/server/simple_action_server.h> 00049 #include <arm_navigation_msgs/MoveArmStatistics.h> 00050 #include <arm_navigation_msgs/MoveArmAction.h> 00051 00052 #include <trajectory_msgs/JointTrajectory.h> 00053 #include <kinematics_msgs/GetConstraintAwarePositionIK.h> 00054 #include <kinematics_msgs/GetPositionFK.h> 00055 00056 #include <arm_navigation_msgs/FilterJointTrajectoryWithConstraints.h> 00057 #include <arm_navigation_msgs/Shape.h> 00058 #include <arm_navigation_msgs/DisplayTrajectory.h> 00059 #include <arm_navigation_msgs/GetMotionPlan.h> 00060 #include <arm_navigation_msgs/convert_messages.h> 00061 #include <arm_navigation_msgs/ArmNavigationErrorCodes.h> 00062 00063 #include <visualization_msgs/Marker.h> 00064 00065 #include <planning_environment/util/construct_object.h> 00066 #include <arm_navigation_msgs/utils.h> 00067 #include <geometric_shapes/bodies.h> 00068 00069 #include <visualization_msgs/MarkerArray.h> 00070 00071 #include <planning_environment/models/collision_models.h> 00072 #include <planning_environment/models/model_utils.h> 00073 #include <arm_navigation_msgs/SetPlanningSceneDiff.h> 00074 00075 #include <arm_navigation_msgs/GetRobotState.h> 00076 00077 #include <actionlib/client/simple_action_client.h> 00078 #include <actionlib/client/simple_client_goal_state.h> 00079 00080 #include <std_msgs/Bool.h> 00081 00082 #include <valarray> 00083 #include <algorithm> 00084 #include <cstdlib> 00085 00086 typedef actionlib::ActionClient<control_msgs::FollowJointTrajectoryAction> JointExecutorActionClient; 00087 00088 namespace move_arm 00089 { 00090 00091 enum MoveArmState { 00092 PLANNING, 00093 START_CONTROL, 00094 VISUALIZE_PLAN, 00095 MONITOR 00096 }; 00097 00098 enum ControllerStatus { 00099 QUEUED, 00100 ACTIVE, 00101 SUCCESS, 00102 FAILED 00103 }; 00104 00105 enum EnvironmentServerChecks{ 00106 COLLISION_TEST = 1, 00107 PATH_CONSTRAINTS_TEST = 2, 00108 GOAL_CONSTRAINTS_TEST = 4, 00109 JOINT_LIMITS_TEST = 8, 00110 CHECK_FULL_TRAJECTORY = 16 00111 }; 00112 00113 typedef struct{ 00114 bool accept_partial_plans; 00115 bool accept_invalid_goals; 00116 bool disable_ik; 00117 bool disable_collision_monitoring; 00118 bool is_pose_goal; 00119 double allowed_planning_time; 00120 std::string planner_service_name; 00121 } MoveArmParameters; 00122 00123 static const std::string ARM_IK_NAME = "arm_ik"; 00124 static const std::string TRAJECTORY_FILTER = "/trajectory_filter_server/filter_trajectory_with_constraints"; 00125 static const std::string DISPLAY_PATH_PUB_TOPIC = "display_path"; 00126 static const std::string DISPLAY_JOINT_GOAL_PUB_TOPIC = "display_joint_goal"; 00127 00128 //bunch of statics for remapping purposes 00129 00130 static const std::string SET_PLANNING_SCENE_DIFF_NAME = "/environment_server/set_planning_scene_diff"; 00131 static const double MIN_TRAJECTORY_MONITORING_FREQUENCY = 1.0; 00132 static const double MAX_TRAJECTORY_MONITORING_FREQUENCY = 100.0; 00133 00134 class MoveArm 00135 { 00136 public: 00137 00138 MoveArm(const std::string &group_name) : 00139 group_(group_name), 00140 private_handle_("~") 00141 { 00142 private_handle_.param<double>("move_arm_frequency",move_arm_frequency_, 50.0); 00143 private_handle_.param<double>("trajectory_filter_allowed_time",trajectory_filter_allowed_time_, 2.0); 00144 private_handle_.param<double>("ik_allowed_time",ik_allowed_time_, 2.0); 00145 00146 private_handle_.param<bool>("publish_stats",publish_stats_, true); 00147 00148 planning_scene_state_ = NULL; 00149 00150 collision_models_ = new planning_environment::CollisionModels("robot_description"); 00151 00152 num_planning_attempts_ = 0; 00153 state_ = PLANNING; 00154 00155 ik_client_ = root_handle_.serviceClient<kinematics_msgs::GetConstraintAwarePositionIK>(ARM_IK_NAME); 00156 allowed_contact_regions_publisher_ = root_handle_.advertise<visualization_msgs::MarkerArray>("allowed_contact_regions_array", 128); 00157 filter_trajectory_client_ = root_handle_.serviceClient<arm_navigation_msgs::FilterJointTrajectoryWithConstraints>(TRAJECTORY_FILTER); 00158 vis_marker_publisher_ = root_handle_.advertise<visualization_msgs::Marker>("move_" + group_name+"_markers", 128); 00159 vis_marker_array_publisher_ = root_handle_.advertise<visualization_msgs::MarkerArray>("move_" + group_name+"_markers_array", 128); 00160 get_state_client_ = root_handle_.serviceClient<arm_navigation_msgs::GetRobotState>("/environment_server/get_robot_state"); 00161 00162 // ros::service::waitForService(ARM_IK_NAME); 00163 arm_ik_initialized_ = false; 00164 ros::service::waitForService(SET_PLANNING_SCENE_DIFF_NAME); 00165 set_planning_scene_diff_client_ = root_handle_.serviceClient<arm_navigation_msgs::SetPlanningSceneDiff>(SET_PLANNING_SCENE_DIFF_NAME); 00166 00167 ros::service::waitForService(TRAJECTORY_FILTER); 00168 00169 action_server_.reset(new actionlib::SimpleActionServer<arm_navigation_msgs::MoveArmAction>(root_handle_, "move_" + group_name, boost::bind(&MoveArm::execute, this, _1), false)); 00170 action_server_->start(); 00171 00172 display_path_publisher_ = root_handle_.advertise<arm_navigation_msgs::DisplayTrajectory>(DISPLAY_PATH_PUB_TOPIC, 1, true); 00173 display_joint_goal_publisher_ = root_handle_.advertise<arm_navigation_msgs::DisplayTrajectory>(DISPLAY_JOINT_GOAL_PUB_TOPIC, 1, true); 00174 stats_publisher_ = private_handle_.advertise<arm_navigation_msgs::MoveArmStatistics>("statistics",1,true); 00175 } 00176 virtual ~MoveArm() 00177 { 00178 revertPlanningScene(); 00179 delete collision_models_; 00180 } 00181 00182 bool configure() 00183 { 00184 if(!initializeControllerInterface()) 00185 { 00186 ROS_ERROR("Could not initialize controller interface"); 00187 return false; 00188 } 00189 if (group_.empty()) 00190 { 00191 ROS_ERROR("No 'group' parameter specified. Without the name of the group of joints to plan for, action cannot start"); 00192 return false; 00193 } 00194 const planning_models::KinematicModel::JointModelGroup* joint_model_group = collision_models_->getKinematicModel()->getModelGroup(group_); 00195 if(joint_model_group == NULL) { 00196 ROS_WARN_STREAM("No joint group " << group_); 00197 return false; 00198 } 00199 group_joint_names_ = joint_model_group->getJointModelNames(); 00200 group_link_names_ = joint_model_group->getGroupLinkNames(); 00201 return true; 00202 } 00203 00204 private: 00205 00209 bool convertPoseGoalToJointGoal(arm_navigation_msgs::GetMotionPlan::Request &req) 00210 { 00211 if(!arm_ik_initialized_) 00212 { 00213 if(!ros::service::waitForService(ARM_IK_NAME,ros::Duration(1.0))) 00214 { 00215 ROS_WARN("Inverse kinematics service is unavailable"); 00216 return false; 00217 } 00218 else 00219 { 00220 arm_ik_initialized_ = true; 00221 } 00222 } 00223 00224 00225 ROS_DEBUG("Acting on goal to pose ...");// we do IK to find corresponding states 00226 ROS_DEBUG("Position constraint: %f %f %f", 00227 req.motion_plan_request.goal_constraints.position_constraints[0].position.x, 00228 req.motion_plan_request.goal_constraints.position_constraints[0].position.y, 00229 req.motion_plan_request.goal_constraints.position_constraints[0].position.z); 00230 ROS_DEBUG("Orientation constraint: %f %f %f %f", 00231 req.motion_plan_request.goal_constraints.orientation_constraints[0].orientation.x, 00232 req.motion_plan_request.goal_constraints.orientation_constraints[0].orientation.y, 00233 req.motion_plan_request.goal_constraints.orientation_constraints[0].orientation.z, 00234 req.motion_plan_request.goal_constraints.orientation_constraints[0].orientation.w); 00235 00236 geometry_msgs::PoseStamped tpose = arm_navigation_msgs::poseConstraintsToPoseStamped(req.motion_plan_request.goal_constraints.position_constraints[0], 00237 req.motion_plan_request.goal_constraints.orientation_constraints[0]); 00238 std::string link_name = req.motion_plan_request.goal_constraints.position_constraints[0].link_name; 00239 sensor_msgs::JointState solution; 00240 00241 ROS_DEBUG("IK request"); 00242 ROS_DEBUG("link_name : %s",link_name.c_str()); 00243 ROS_DEBUG("frame_id : %s",tpose.header.frame_id.c_str()); 00244 ROS_DEBUG("position : (%f,%f,%f)",tpose.pose.position.x,tpose.pose.position.y,tpose.pose.position.z); 00245 ROS_DEBUG("orientation : (%f,%f,%f,%f)",tpose.pose.orientation.x,tpose.pose.orientation.y,tpose.pose.orientation.z,tpose.pose.orientation.w); 00246 ROS_DEBUG(" "); 00247 if (computeIK(tpose, 00248 link_name, 00249 solution)) 00250 { 00251 std::map<std::string, double> joint_values; 00252 for (unsigned int i = 0 ; i < solution.name.size() ; ++i) 00253 { 00254 arm_navigation_msgs::JointConstraint jc; 00255 jc.joint_name = solution.name[i]; 00256 jc.position = solution.position[i]; 00257 jc.tolerance_below = 0.01; 00258 jc.tolerance_above = 0.01; 00259 req.motion_plan_request.goal_constraints.joint_constraints.push_back(jc); 00260 joint_values[jc.joint_name] = jc.position; 00261 } 00262 arm_navigation_msgs::ArmNavigationErrorCodes error_code; 00263 resetToStartState(planning_scene_state_); 00264 planning_scene_state_->setKinematicState(joint_values); 00265 if(!collision_models_->isKinematicStateValid(*planning_scene_state_, 00266 group_joint_names_, 00267 error_code, 00268 original_request_.motion_plan_request.goal_constraints, 00269 original_request_.motion_plan_request.path_constraints, 00270 true)) 00271 { 00272 ROS_INFO("IK returned joint state for goal that doesn't seem to be valid"); 00273 if(error_code.val == error_code.GOAL_CONSTRAINTS_VIOLATED) { 00274 ROS_WARN("IK solution doesn't obey goal constraints"); 00275 } else if(error_code.val == error_code.COLLISION_CONSTRAINTS_VIOLATED) { 00276 ROS_WARN("IK solution in collision"); 00277 } else { 00278 ROS_WARN_STREAM("Some other problem with ik solution " << error_code.val); 00279 } 00280 } 00281 req.motion_plan_request.goal_constraints.position_constraints.clear(); 00282 req.motion_plan_request.goal_constraints.orientation_constraints.clear(); 00283 return true; 00284 } 00285 else 00286 return false; 00287 } 00288 00289 bool computeIK(const geometry_msgs::PoseStamped &pose_stamped_msg, 00290 const std::string &link_name, 00291 sensor_msgs::JointState &solution) 00292 { 00293 kinematics_msgs::GetConstraintAwarePositionIK::Request request; 00294 kinematics_msgs::GetConstraintAwarePositionIK::Response response; 00295 00296 request.ik_request.pose_stamped = pose_stamped_msg; 00297 request.ik_request.robot_state = original_request_.motion_plan_request.start_state; 00298 request.ik_request.ik_seed_state = request.ik_request.robot_state; 00299 request.ik_request.ik_link_name = link_name; 00300 request.timeout = ros::Duration(ik_allowed_time_); 00301 request.constraints = original_request_.motion_plan_request.goal_constraints; 00302 if (ik_client_.call(request, response)) 00303 { 00304 move_arm_action_result_.error_code = response.error_code; 00305 if(response.error_code.val != response.error_code.SUCCESS) 00306 { 00307 ROS_ERROR("IK Solution not found, IK returned with error_code: %d",response.error_code.val); 00308 return false; 00309 } 00310 solution = response.solution.joint_state; 00311 if (solution.position.size() != group_joint_names_.size()) 00312 { 00313 ROS_ERROR("Incorrect number of elements in IK output."); 00314 return false; 00315 } 00316 for(unsigned int i = 0; i < solution.position.size() ; ++i) 00317 ROS_DEBUG("IK[%d] = %f", (int)i, solution.position[i]); 00318 } 00319 else 00320 { 00321 ROS_ERROR("IK service failed"); 00322 return false; 00323 } 00324 return true; 00325 } 00329 00333 bool filterTrajectory(const trajectory_msgs::JointTrajectory &trajectory_in, 00334 trajectory_msgs::JointTrajectory &trajectory_out) 00335 { 00336 arm_navigation_msgs::FilterJointTrajectoryWithConstraints::Request req; 00337 arm_navigation_msgs::FilterJointTrajectoryWithConstraints::Response res; 00338 fillTrajectoryMsg(trajectory_in, req.trajectory); 00339 00340 if(trajectory_filter_allowed_time_ == 0.0) 00341 { 00342 trajectory_out = req.trajectory; 00343 return true; 00344 } 00345 resetToStartState(planning_scene_state_); 00346 planning_environment::convertKinematicStateToRobotState(*planning_scene_state_, 00347 ros::Time::now(), 00348 collision_models_->getWorldFrameId(), 00349 req.start_state); 00350 req.group_name = group_; 00351 req.path_constraints = original_request_.motion_plan_request.path_constraints; 00352 req.goal_constraints = original_request_.motion_plan_request.goal_constraints; 00353 req.allowed_time = ros::Duration(trajectory_filter_allowed_time_); 00354 ros::Time smoothing_time = ros::Time::now(); 00355 if(filter_trajectory_client_.call(req,res)) 00356 { 00357 move_arm_stats_.trajectory_duration = (res.trajectory.points.back().time_from_start-res.trajectory.points.front().time_from_start).toSec(); 00358 move_arm_stats_.smoothing_time = (ros::Time::now()-smoothing_time).toSec(); 00359 trajectory_out = res.trajectory; 00360 return true; 00361 } 00362 else 00363 { 00364 ROS_ERROR("Service call to filter trajectory failed."); 00365 return false; 00366 } 00367 } 00368 00372 00373 void discretizeTrajectory(const trajectory_msgs::JointTrajectory &trajectory, 00374 trajectory_msgs::JointTrajectory &trajectory_out, 00375 const double &trajectory_discretization) 00376 { 00377 trajectory_out.joint_names = trajectory.joint_names; 00378 for(unsigned int i=1; i < trajectory.points.size(); i++) 00379 { 00380 double diff = 0.0; 00381 for(unsigned int j=0; j < trajectory.points[i].positions.size(); j++) 00382 { 00383 double start = trajectory.points[i-1].positions[j]; 00384 double end = trajectory.points[i].positions[j]; 00385 if(fabs(end-start) > diff) 00386 diff = fabs(end-start); 00387 } 00388 int num_intervals =(int) (diff/trajectory_discretization+1.0); 00389 00390 for(unsigned int k=0; k < (unsigned int) num_intervals; k++) 00391 { 00392 trajectory_msgs::JointTrajectoryPoint point; 00393 for(unsigned int j=0; j < trajectory.points[i].positions.size(); j++) 00394 { 00395 double start = trajectory.points[i-1].positions[j]; 00396 double end = trajectory.points[i].positions[j]; 00397 point.positions.push_back(start + (end-start)*k/num_intervals); 00398 } 00399 point.time_from_start = ros::Duration(trajectory.points[i].time_from_start.toSec() + k* (trajectory.points[i].time_from_start - trajectory.points[i-1].time_from_start).toSec()/num_intervals); 00400 trajectory_out.points.push_back(point); 00401 } 00402 } 00403 trajectory_out.points.push_back(trajectory.points.back()); 00404 } 00408 00412 bool isPoseGoal(arm_navigation_msgs::GetMotionPlan::Request &req) 00413 { 00414 if (req.motion_plan_request.goal_constraints.joint_constraints.empty() && // we have no joint constraints on the goal, 00415 req.motion_plan_request.goal_constraints.position_constraints.size() == 1 && // we have a single position constraint on the goal 00416 req.motion_plan_request.goal_constraints.orientation_constraints.size() == 1) // that is active on all 6 DOFs 00417 return true; 00418 else 00419 return false; 00420 } 00421 bool hasPoseGoal(arm_navigation_msgs::GetMotionPlan::Request &req) 00422 { 00423 if (req.motion_plan_request.goal_constraints.position_constraints.size() >= 1 && // we have a single position constraint on the goal 00424 req.motion_plan_request.goal_constraints.orientation_constraints.size() >= 1) // that is active on all 6 DOFs 00425 return true; 00426 else 00427 return false; 00428 } 00429 bool isJointGoal(arm_navigation_msgs::GetMotionPlan::Request &req) 00430 { 00431 if (req.motion_plan_request.goal_constraints.position_constraints.empty() && 00432 req.motion_plan_request.goal_constraints.orientation_constraints.empty() && 00433 !req.motion_plan_request.goal_constraints.joint_constraints.empty()) 00434 return true; 00435 else 00436 return false; 00437 } 00438 00439 //stubbing out for now 00440 bool isExecutionSafe() { 00441 return true; 00442 } 00443 00444 bool getRobotState(planning_models::KinematicState* state) 00445 { 00446 arm_navigation_msgs::GetRobotState::Request req; 00447 arm_navigation_msgs::GetRobotState::Response res; 00448 if(get_state_client_.call(req,res)) 00449 { 00450 planning_environment::setRobotStateAndComputeTransforms(res.robot_state, *state); 00451 } 00452 else 00453 { 00454 ROS_ERROR("Service call to get robot state failed on %s", 00455 get_state_client_.getService().c_str()); 00456 return false; 00457 } 00458 return true; 00459 } 00463 00467 void moveArmGoalToPlannerRequest(const arm_navigation_msgs::MoveArmGoalConstPtr& goal, 00468 arm_navigation_msgs::GetMotionPlan::Request &req) 00469 { 00470 req.motion_plan_request.workspace_parameters.workspace_region_pose.header.stamp = ros::Time::now(); 00471 req.motion_plan_request = goal->motion_plan_request; 00472 00473 move_arm_parameters_.accept_partial_plans = goal->accept_partial_plans; 00474 move_arm_parameters_.accept_invalid_goals = goal->accept_invalid_goals; 00475 move_arm_parameters_.disable_ik = goal->disable_ik; 00476 move_arm_parameters_.disable_collision_monitoring = goal->disable_collision_monitoring; 00477 move_arm_parameters_.allowed_planning_time = goal->motion_plan_request.allowed_planning_time.toSec(); 00478 move_arm_parameters_.planner_service_name = goal->planner_service_name; 00479 // visualizeAllowedContactRegions(req.motion_plan_request.allowed_contacts); 00480 // ROS_INFO("Move arm: %d allowed contact regions",(int)req.motion_plan_request.allowed_contacts.size()); 00481 // for(unsigned int i=0; i < req.motion_plan_request.allowed_contacts.size(); i++) 00482 // { 00483 // ROS_INFO("Position : (%f,%f,%f)",req.motion_plan_request.allowed_contacts[i].pose_stamped.pose.position.x,req.motion_plan_request.allowed_contacts[i].pose_stamped.pose.position.y,req.motion_plan_request.allowed_contacts[i].pose_stamped.pose.position.z); 00484 // ROS_INFO("Frame id : %s",req.motion_plan_request.allowed_contacts[i].pose_stamped.header.frame_id.c_str()); 00485 // ROS_INFO("Depth : %f",req.motion_plan_request.allowed_contacts[i].penetration_depth); 00486 // ROS_INFO("Link : %s",req.motion_plan_request.allowed_contacts[i].link_names[0].c_str()); 00487 // ROS_INFO(" "); 00488 // } 00489 } 00490 bool doPrePlanningChecks(arm_navigation_msgs::GetMotionPlan::Request &req, 00491 arm_navigation_msgs::GetMotionPlan::Response &res) 00492 { 00493 arm_navigation_msgs::Constraints empty_goal_constraints; 00494 if(planning_scene_state_ == NULL) { 00495 ROS_INFO("Can't do pre-planning checks without planning state"); 00496 } 00497 resetToStartState(planning_scene_state_); 00498 arm_navigation_msgs::ArmNavigationErrorCodes error_code; 00499 if(!collision_models_->isKinematicStateValid(*planning_scene_state_, 00500 group_joint_names_, 00501 error_code, 00502 empty_goal_constraints, 00503 original_request_.motion_plan_request.path_constraints, 00504 true)) { 00505 if(error_code.val == error_code.COLLISION_CONSTRAINTS_VIOLATED) { 00506 move_arm_action_result_.error_code.val = error_code.START_STATE_IN_COLLISION; 00507 collision_models_->getAllCollisionsForState(*planning_scene_state_, 00508 move_arm_action_result_.contacts); 00509 ROS_ERROR("Starting state is in collision, can't plan"); 00510 visualization_msgs::MarkerArray arr; 00511 std_msgs::ColorRGBA point_color_; 00512 point_color_.a = 1.0; 00513 point_color_.r = 1.0; 00514 point_color_.g = .8; 00515 point_color_.b = 0.04; 00516 00517 collision_models_->getAllCollisionPointMarkers(*planning_scene_state_, 00518 arr, 00519 point_color_, 00520 ros::Duration(0.0)); 00521 std_msgs::ColorRGBA col; 00522 col.a = .9; 00523 col.r = 1.0; 00524 col.b = 1.0; 00525 col.g = 0.0; 00526 /* 00527 collision_models_->getRobotTrimeshMarkersGivenState(*planning_scene_state_, 00528 arr, 00529 true, 00530 ros::Duration(0.0)); 00531 */ 00532 vis_marker_array_publisher_.publish(arr); 00533 } else if (error_code.val == error_code.PATH_CONSTRAINTS_VIOLATED) { 00534 move_arm_action_result_.error_code.val = error_code.START_STATE_VIOLATES_PATH_CONSTRAINTS; 00535 ROS_ERROR("Starting state violated path constraints, can't plan");; 00536 } else if (error_code.val == error_code.JOINT_LIMITS_VIOLATED) { 00537 move_arm_action_result_.error_code.val = move_arm_action_result_.error_code.JOINT_LIMITS_VIOLATED;; 00538 ROS_ERROR("Start state violates joint limits, can't plan."); 00539 } 00540 ROS_INFO("Setting aborted because start state invalid"); 00541 action_server_->setAborted(move_arm_action_result_); 00542 return false; 00543 } 00544 // processing and checking goal 00545 if (!move_arm_parameters_.disable_ik && isPoseGoal(req)) { 00546 ROS_DEBUG("Planning to a pose goal"); 00547 if(!convertPoseGoalToJointGoal(req)) { 00548 ROS_INFO("Setting aborted because ik failed"); 00549 action_server_->setAborted(move_arm_action_result_); 00550 return false; 00551 } 00552 } 00553 //if we still have pose constraints at this point it's probably a constrained combo goal 00554 if(!hasPoseGoal(req)) { 00555 arm_navigation_msgs::RobotState empty_state; 00556 empty_state.joint_state = arm_navigation_msgs::jointConstraintsToJointState(req.motion_plan_request.goal_constraints.joint_constraints); 00557 planning_environment::setRobotStateAndComputeTransforms(empty_state, *planning_scene_state_); 00558 arm_navigation_msgs::Constraints empty_constraints; 00559 if(!collision_models_->isKinematicStateValid(*planning_scene_state_, 00560 group_joint_names_, 00561 error_code, 00562 original_request_.motion_plan_request.goal_constraints, 00563 original_request_.motion_plan_request.path_constraints, 00564 true)) { 00565 if(error_code.val == error_code.JOINT_LIMITS_VIOLATED) { 00566 ROS_ERROR("Will not plan to requested joint goal since it violates joint limits constraints"); 00567 move_arm_action_result_.error_code.val = move_arm_action_result_.error_code.JOINT_LIMITS_VIOLATED; 00568 } else if(error_code.val == error_code.COLLISION_CONSTRAINTS_VIOLATED) { 00569 ROS_ERROR("Will not plan to requested joint goal since it is in collision"); 00570 move_arm_action_result_.error_code.val = move_arm_action_result_.error_code.GOAL_IN_COLLISION; 00571 collision_models_->getAllCollisionsForState(*planning_scene_state_, 00572 move_arm_action_result_.contacts); 00573 } else if(error_code.val == error_code.GOAL_CONSTRAINTS_VIOLATED) { 00574 ROS_ERROR("Will not plan to requested joint goal since it violates goal constraints"); 00575 move_arm_action_result_.error_code.val = move_arm_action_result_.error_code.GOAL_VIOLATES_PATH_CONSTRAINTS; 00576 } else if(error_code.val == error_code.PATH_CONSTRAINTS_VIOLATED) { 00577 ROS_ERROR("Will not plan to requested joint goal since it violates path constraints"); 00578 move_arm_action_result_.error_code.val = move_arm_action_result_.error_code.GOAL_VIOLATES_PATH_CONSTRAINTS; 00579 } else { 00580 ROS_INFO_STREAM("Will not plan to request joint goal due to error code " << error_code.val); 00581 } 00582 ROS_INFO_STREAM("Setting aborted becuase joint goal is problematic"); 00583 action_server_->setAborted(move_arm_action_result_); 00584 return false; 00585 } 00586 } 00587 return true; 00588 } 00589 00590 bool createPlan(arm_navigation_msgs::GetMotionPlan::Request &req, 00591 arm_navigation_msgs::GetMotionPlan::Response &res) 00592 { 00593 while(!ros::service::waitForService(move_arm_parameters_.planner_service_name, ros::Duration(1.0))) { 00594 ROS_INFO_STREAM("Waiting for requested service " << move_arm_parameters_.planner_service_name); 00595 } 00596 ros::ServiceClient planning_client = root_handle_.serviceClient<arm_navigation_msgs::GetMotionPlan>(move_arm_parameters_.planner_service_name); 00597 move_arm_stats_.planner_service_name = move_arm_parameters_.planner_service_name; 00598 ROS_DEBUG("Issuing request for motion plan"); 00599 // call the planner and decide whether to use the path 00600 if (planning_client.call(req, res)) 00601 { 00602 if (res.trajectory.joint_trajectory.points.empty()) 00603 { 00604 ROS_WARN("Motion planner was unable to plan a path to goal"); 00605 return false; 00606 } 00607 ROS_DEBUG("Motion planning succeeded"); 00608 return true; 00609 } 00610 else 00611 { 00612 ROS_ERROR("Motion planning service failed on %s",planning_client.getService().c_str()); 00613 return false; 00614 } 00615 } 00619 00623 bool initializeControllerInterface() 00624 { 00625 std::string controller_action_name; 00626 private_handle_.param<std::string>("controller_action_name", controller_action_name, "action"); 00627 ROS_INFO("Connecting to controller using action: %s",controller_action_name.c_str()); 00628 controller_action_client_ = new JointExecutorActionClient(controller_action_name); 00629 if(!controller_action_client_) { 00630 ROS_ERROR("Controller action client hasn't been initialized yet"); 00631 return false; 00632 } 00633 while(!controller_action_client_->waitForActionServerToStart(ros::Duration(1.0))){ 00634 ROS_INFO("Waiting for the joint_trajectory_action server to come up."); 00635 if(!root_handle_.ok()) { 00636 return false; 00637 } 00638 } 00639 ROS_INFO("Connected to the controller"); 00640 return true; 00641 } 00642 00643 00644 bool stopTrajectory() 00645 { 00646 if (controller_goal_handle_.isExpired()) 00647 ROS_ERROR("Expired goal handle. controller_status = %d", controller_status_); 00648 else 00649 controller_goal_handle_.cancel(); 00650 return true; 00651 } 00652 bool sendTrajectory(trajectory_msgs::JointTrajectory ¤t_trajectory) 00653 { 00654 current_trajectory.header.stamp = ros::Time::now()+ros::Duration(0.2); 00655 00656 control_msgs::FollowJointTrajectoryGoal goal; 00657 goal.trajectory = current_trajectory; 00658 00659 ROS_DEBUG("Sending trajectory with %d points and timestamp: %f",(int)goal.trajectory.points.size(),goal.trajectory.header.stamp.toSec()); 00660 for(unsigned int i=0; i < goal.trajectory.joint_names.size(); i++) 00661 ROS_DEBUG("Joint: %d name: %s",i,goal.trajectory.joint_names[i].c_str()); 00662 00663 /* for(unsigned int i = 0; i < goal.trajectory.points.size(); i++) 00664 { 00665 ROS_INFO("%f: %f %f %f %f %f %f %f %f %f %f %f %f %f %f", 00666 goal.trajectory.points[i].time_from_start.toSec(), 00667 goal.trajectory.points[i].positions[0], 00668 goal.trajectory.points[i].positions[1], 00669 goal.trajectory.points[i].positions[2], 00670 goal.trajectory.points[i].positions[3], 00671 goal.trajectory.points[i].positions[4], 00672 goal.trajectory.points[i].positions[5], 00673 goal.trajectory.points[i].positions[6], 00674 goal.trajectory.points[i].velocities[0], 00675 goal.trajectory.points[i].velocities[1], 00676 goal.trajectory.points[i].velocities[2], 00677 goal.trajectory.points[i].velocities[3], 00678 goal.trajectory.points[i].velocities[4], 00679 goal.trajectory.points[i].velocities[5], 00680 goal.trajectory.points[i].velocities[6]); 00681 }*/ 00682 controller_goal_handle_ = controller_action_client_->sendGoal(goal,boost::bind(&MoveArm::controllerTransitionCallback, this, _1)); 00683 00684 controller_status_ = QUEUED; 00685 // printTrajectory(goal.trajectory); 00686 return true; 00687 } 00688 00689 void controllerTransitionCallback(JointExecutorActionClient::GoalHandle gh) 00690 { 00691 if(gh != controller_goal_handle_) 00692 return; 00693 actionlib::CommState comm_state = gh.getCommState(); 00694 switch( comm_state.state_) 00695 { 00696 case actionlib::CommState::WAITING_FOR_GOAL_ACK: 00697 case actionlib::CommState::PENDING: 00698 case actionlib::CommState::RECALLING: 00699 controller_status_ = QUEUED; 00700 return; 00701 case actionlib:: CommState::ACTIVE: 00702 case actionlib::CommState::PREEMPTING: 00703 controller_status_ = ACTIVE; 00704 return; 00705 case actionlib::CommState::DONE: 00706 { 00707 switch(gh.getTerminalState().state_) 00708 { 00709 case actionlib::TerminalState::RECALLED: 00710 case actionlib::TerminalState::REJECTED: 00711 case actionlib::TerminalState::PREEMPTED: 00712 case actionlib::TerminalState::ABORTED: 00713 case actionlib::TerminalState::LOST: 00714 { 00715 ROS_INFO("Trajectory controller status came back as failed"); 00716 controller_status_ = FAILED; 00717 controller_goal_handle_.reset(); 00718 return; 00719 } 00720 case actionlib::TerminalState::SUCCEEDED: 00721 { 00722 controller_goal_handle_.reset(); 00723 controller_status_ = SUCCESS; 00724 return; 00725 } 00726 default: 00727 ROS_ERROR("Unknown terminal state [%u]. This is a bug in ActionClient", gh.getTerminalState().state_); 00728 } 00729 } 00730 default: 00731 break; 00732 } 00733 } 00734 bool isControllerDone(arm_navigation_msgs::ArmNavigationErrorCodes& error_code) 00735 { 00736 if (controller_status_ == SUCCESS) 00737 { 00738 error_code.val = error_code.SUCCESS; 00739 return true; 00740 } else if(controller_status_ == FAILED) 00741 { 00742 error_code.val = error_code.TRAJECTORY_CONTROLLER_FAILED; 00743 return true; 00744 } else { 00745 return false; 00746 } 00747 } 00748 00749 void fillTrajectoryMsg(const trajectory_msgs::JointTrajectory &trajectory_in, 00750 trajectory_msgs::JointTrajectory &trajectory_out) 00751 { 00752 trajectory_out = trajectory_in; 00753 if(trajectory_in.points.empty()) 00754 { 00755 ROS_WARN("No points in trajectory"); 00756 return; 00757 } 00758 // get the current state 00759 double d = 0.0; 00760 00761 00762 std::map<std::string, double> val_map; 00763 resetToStartState(planning_scene_state_); 00764 planning_scene_state_->getKinematicStateValues(val_map); 00765 sensor_msgs::JointState current; 00766 current.name = trajectory_out.joint_names; 00767 current.position.resize(trajectory_out.joint_names.size()); 00768 for(unsigned int i = 0; i < trajectory_out.joint_names.size(); i++) { 00769 current.position[i] = val_map[trajectory_out.joint_names[i]]; 00770 } 00771 std::map<std::string, bool> continuous; 00772 for(unsigned int j = 0; j < trajectory_in.joint_names.size(); j++) { 00773 std::string name = trajectory_in.joint_names[j]; 00774 boost::shared_ptr<const urdf::Joint> joint = collision_models_->getParsedDescription()->getJoint(name); 00775 if (joint.get() == NULL) 00776 { 00777 ROS_ERROR("Joint name %s not found in urdf model", name.c_str()); 00778 return; 00779 } 00780 if (joint->type == urdf::Joint::CONTINUOUS) { 00781 continuous[name] = true; 00782 } else { 00783 continuous[name] = false; 00784 } 00785 } 00786 for (unsigned int i = 0 ; i < current.position.size() ; ++i) 00787 { 00788 double diff; 00789 if(!continuous[trajectory_in.joint_names[i]]) { 00790 diff = fabs(trajectory_in.points[0].positions[i] - val_map[trajectory_in.joint_names[i]]); 00791 } else { 00792 diff = angles::shortest_angular_distance(trajectory_in.points[0].positions[i],val_map[trajectory_in.joint_names[i]]); 00793 } 00794 d += diff * diff; 00795 } 00796 d = sqrt(d); 00797 // decide whether we place the current state in front of the trajectory_in 00798 int include_first = (d > 0.1) ? 1 : 0; 00799 double offset = 0.0; 00800 trajectory_out.points.resize(trajectory_in.points.size() + include_first); 00801 00802 if (include_first) 00803 { 00804 ROS_INFO("Adding current state to front of trajectory"); 00805 // ROS_INFO_STREAM("Old state " << trajectory_out.points[0].positions[0] 00806 // << trajectory_out.points[0].positions[1] 00807 // << trajectory_out.points[0].positions[2] 00808 // << trajectory_out.points[0].positions[3] 00809 // << trajectory_out.points[0].positions[4] 00810 // << trajectory_out.points[0].positions[5] 00811 // << trajectory_out.points[0].positions[6]); 00812 00813 // ROS_INFO_STREAM("Current state " << current.position[0] 00814 // << current.position[1] 00815 // << current.position[2] 00816 // << current.position[3] 00817 // << current.position[4] 00818 // << current.position[5] 00819 // << current.position[6]); 00820 trajectory_out.points[0].positions = arm_navigation_msgs::jointStateToJointTrajectoryPoint(current).positions; 00821 trajectory_out.points[0].time_from_start = ros::Duration(0.0); 00822 offset = 0.3 + d; 00823 } 00824 for (unsigned int i = 0 ; i < trajectory_in.points.size() ; ++i) 00825 { 00826 trajectory_out.points[i+include_first].time_from_start = trajectory_in.points[i].time_from_start; 00827 trajectory_out.points[i+include_first].positions = trajectory_in.points[i].positions; 00828 } 00829 trajectory_out.header.stamp = ros::Time::now(); 00830 } 00831 00835 00839 void resetStateMachine() 00840 { 00841 num_planning_attempts_ = 0; 00842 current_trajectory_.points.clear(); 00843 current_trajectory_.joint_names.clear(); 00844 state_ = PLANNING; 00845 } 00846 bool executeCycle(arm_navigation_msgs::GetMotionPlan::Request &req) 00847 { 00848 arm_navigation_msgs::GetMotionPlan::Response res; 00849 arm_navigation_msgs::ArmNavigationErrorCodes error_code; 00850 00851 switch(state_) 00852 { 00853 case PLANNING: 00854 { 00855 move_arm_action_feedback_.state = "planning"; 00856 move_arm_action_feedback_.time_to_completion = ros::Duration(req.motion_plan_request.allowed_planning_time); 00857 action_server_->publishFeedback(move_arm_action_feedback_); 00858 00859 if(!doPrePlanningChecks(req,res)) 00860 return true; 00861 00862 visualizeJointGoal(req); 00863 resetToStartState(planning_scene_state_); 00864 if(collision_models_->isKinematicStateValid(*planning_scene_state_, 00865 group_joint_names_, 00866 error_code, 00867 original_request_.motion_plan_request.goal_constraints, 00868 original_request_.motion_plan_request.path_constraints, 00869 false)) { 00870 resetStateMachine(); 00871 move_arm_action_result_.error_code.val = move_arm_action_result_.error_code.SUCCESS; 00872 action_server_->setSucceeded(move_arm_action_result_); 00873 ROS_INFO("Apparently start state satisfies goal"); 00874 return true; 00875 } 00876 ros::Time planning_time = ros::Time::now(); 00877 if(createPlan(req,res)) 00878 { 00879 std::vector<arm_navigation_msgs::ArmNavigationErrorCodes> traj_error_codes; 00880 move_arm_stats_.planning_time = (ros::Time::now()-planning_time).toSec(); 00881 ROS_DEBUG("createPlan succeeded"); 00882 resetToStartState(planning_scene_state_); 00883 if(!collision_models_->isJointTrajectoryValid(*planning_scene_state_, 00884 res.trajectory.joint_trajectory, 00885 original_request_.motion_plan_request.goal_constraints, 00886 original_request_.motion_plan_request.path_constraints, 00887 error_code, 00888 traj_error_codes, 00889 true)) 00890 { 00891 if(error_code.val == error_code.COLLISION_CONSTRAINTS_VIOLATED) { 00892 ROS_WARN("Planner trajectory collides"); 00893 } else if (error_code.val == error_code.PATH_CONSTRAINTS_VIOLATED) { 00894 ROS_WARN("Planner trajectory violates path constraints"); 00895 } else if (error_code.val == error_code.JOINT_LIMITS_VIOLATED) { 00896 ROS_WARN("Planner trajectory violates joint limits"); 00897 } else if (error_code.val == error_code.GOAL_CONSTRAINTS_VIOLATED) { 00898 ROS_WARN("Planner trajectory doesn't reach goal"); 00899 } 00900 num_planning_attempts_++; 00901 if(num_planning_attempts_ > req.motion_plan_request.num_planning_attempts) 00902 { 00903 resetStateMachine(); 00904 ROS_INFO_STREAM("Setting aborted because we're out of planning attempts"); 00905 action_server_->setAborted(move_arm_action_result_); 00906 return true; 00907 } 00908 } 00909 else{ 00910 ROS_DEBUG("Trajectory validity check was successful"); 00911 00912 current_trajectory_ = res.trajectory.joint_trajectory; 00913 visualizePlan(current_trajectory_); 00914 // printTrajectory(current_trajectory_); 00915 state_ = START_CONTROL; 00916 ROS_DEBUG("Done planning. Transitioning to control"); 00917 } 00918 } 00919 else if(action_server_->isActive()) 00920 { 00921 num_planning_attempts_++; 00922 arm_navigation_msgs::ArmNavigationErrorCodes error_code; 00923 error_code.val = error_code.PLANNING_FAILED; 00924 if(num_planning_attempts_ > req.motion_plan_request.num_planning_attempts) 00925 { 00926 resetStateMachine(); 00927 ROS_INFO_STREAM("Setting aborted because we're out of planning attempts"); 00928 action_server_->setAborted(move_arm_action_result_); 00929 return true; 00930 } 00931 } 00932 else 00933 { 00934 ROS_ERROR("create plan failed"); 00935 } 00936 break; 00937 } 00938 case START_CONTROL: 00939 { 00940 move_arm_action_feedback_.state = "start_control"; 00941 move_arm_action_feedback_.time_to_completion = ros::Duration(1.0/move_arm_frequency_); 00942 action_server_->publishFeedback(move_arm_action_feedback_); 00943 ROS_DEBUG("Filtering Trajectory"); 00944 trajectory_msgs::JointTrajectory filtered_trajectory; 00945 if(filterTrajectory(current_trajectory_, filtered_trajectory)) 00946 { 00947 arm_navigation_msgs::ArmNavigationErrorCodes error_code; 00948 std::vector<arm_navigation_msgs::ArmNavigationErrorCodes> traj_error_codes; 00949 resetToStartState(planning_scene_state_); 00950 if(!collision_models_->isJointTrajectoryValid(*planning_scene_state_, 00951 filtered_trajectory, 00952 original_request_.motion_plan_request.goal_constraints, 00953 original_request_.motion_plan_request.path_constraints, 00954 error_code, 00955 traj_error_codes, 00956 false)) 00957 { 00958 if(error_code.val == error_code.COLLISION_CONSTRAINTS_VIOLATED) { 00959 ROS_WARN("Filtered trajectory collides"); 00960 } else if (error_code.val == error_code.PATH_CONSTRAINTS_VIOLATED) { 00961 ROS_WARN("Filtered trajectory violates path constraints"); 00962 } else if (error_code.val == error_code.JOINT_LIMITS_VIOLATED) { 00963 ROS_WARN("Filtered trajectory violates joint limits"); 00964 } else if (error_code.val == error_code.GOAL_CONSTRAINTS_VIOLATED) { 00965 ROS_WARN("Filtered trajectory doesn't reach goal"); 00966 } 00967 ROS_ERROR("Move arm will abort this goal. Will replan"); 00968 state_ = PLANNING; 00969 num_planning_attempts_++; 00970 if(num_planning_attempts_ > req.motion_plan_request.num_planning_attempts) 00971 { 00972 resetStateMachine(); 00973 ROS_INFO_STREAM("Setting aborted because we're out of planning attempts"); 00974 action_server_->setAborted(move_arm_action_result_); 00975 return true; 00976 } 00977 //resetStateMachine(); 00978 //action_server_->setAborted(move_arm_action_result_); 00979 break; 00980 //return true; 00981 } 00982 else{ 00983 ROS_DEBUG("Trajectory validity check was successful"); 00984 } 00985 current_trajectory_ = filtered_trajectory; 00986 } else { 00987 resetStateMachine(); 00988 ROS_INFO_STREAM("Setting aborted because trajectory filter call failed"); 00989 action_server_->setAborted(move_arm_action_result_); 00990 return true; 00991 } 00992 ROS_DEBUG("Sending trajectory"); 00993 move_arm_stats_.time_to_execution = (ros::Time::now() - ros::Time(move_arm_stats_.time_to_execution)).toSec(); 00994 if(sendTrajectory(current_trajectory_)) 00995 { 00996 state_ = MONITOR; 00997 } 00998 else 00999 { 01000 resetStateMachine(); 01001 ROS_INFO("Setting aborted because we couldn't send the trajectory"); 01002 action_server_->setAborted(move_arm_action_result_); 01003 return true; 01004 } 01005 break; 01006 } 01007 case MONITOR: 01008 { 01009 move_arm_action_feedback_.state = "monitor"; 01010 move_arm_action_feedback_.time_to_completion = current_trajectory_.points.back().time_from_start; 01011 action_server_->publishFeedback(move_arm_action_feedback_); 01012 ROS_DEBUG("Start to monitor"); 01013 arm_navigation_msgs::ArmNavigationErrorCodes controller_error_code; 01014 if(isControllerDone(controller_error_code)) 01015 { 01016 move_arm_stats_.time_to_result = (ros::Time::now()-ros::Time(move_arm_stats_.time_to_result)).toSec(); 01017 01018 arm_navigation_msgs::RobotState empty_state; 01019 arm_navigation_msgs::ArmNavigationErrorCodes state_error_code; 01020 getRobotState(planning_scene_state_); 01021 if(collision_models_->isKinematicStateValid(*planning_scene_state_, 01022 group_joint_names_, 01023 state_error_code, 01024 original_request_.motion_plan_request.goal_constraints, 01025 original_request_.motion_plan_request.path_constraints, 01026 true)) 01027 { 01028 move_arm_action_result_.error_code.val = move_arm_action_result_.error_code.SUCCESS; 01029 resetStateMachine(); 01030 action_server_->setSucceeded(move_arm_action_result_); 01031 if(controller_error_code.val == controller_error_code.TRAJECTORY_CONTROLLER_FAILED) { 01032 ROS_INFO("Trajectory controller failed but we seem to be at goal"); 01033 } else { 01034 ROS_DEBUG("Reached goal"); 01035 } 01036 return true; 01037 } 01038 else 01039 { 01040 if(state_error_code.val == state_error_code.COLLISION_CONSTRAINTS_VIOLATED) { 01041 move_arm_action_result_.error_code.val = state_error_code.START_STATE_IN_COLLISION; 01042 collision_models_->getAllCollisionsForState(*planning_scene_state_, 01043 move_arm_action_result_.contacts); 01044 ROS_WARN("Though trajectory is done current state is in collision"); 01045 } else if (state_error_code.val == state_error_code.PATH_CONSTRAINTS_VIOLATED) { 01046 ROS_WARN("Though trajectory is done current state violates path constraints"); 01047 } else if (state_error_code.val == state_error_code.JOINT_LIMITS_VIOLATED) { 01048 ROS_WARN("Though trajectory is done current state violates joint limits"); 01049 } else if(state_error_code.val == state_error_code.GOAL_CONSTRAINTS_VIOLATED) { 01050 ROS_WARN("Though trajectory is done current state does not seem to be at goal"); 01051 } 01052 resetStateMachine(); 01053 action_server_->setAborted(move_arm_action_result_); 01054 ROS_INFO("Monitor done but not in good state"); 01055 return true; 01056 } 01057 } 01058 break; 01059 } 01060 default: 01061 { 01062 ROS_INFO("Should not be here."); 01063 break; 01064 } 01065 } 01066 if(!action_server_->isActive()) 01067 { 01068 ROS_DEBUG("Move arm no longer has an active goal"); 01069 return true; 01070 } 01071 return false; 01072 } 01073 void execute(const arm_navigation_msgs::MoveArmGoalConstPtr& goal) 01074 { 01075 arm_navigation_msgs::GetMotionPlan::Request req; 01076 moveArmGoalToPlannerRequest(goal,req); 01077 01078 if(!getAndSetPlanningScene(goal->planning_scene_diff, goal->operations)) { 01079 ROS_INFO("Problem setting planning scene"); 01080 move_arm_action_result_.error_code.val = move_arm_action_result_.error_code.INCOMPLETE_ROBOT_STATE; 01081 action_server_->setAborted(move_arm_action_result_); 01082 return; 01083 } 01084 01085 collision_models_->convertConstraintsGivenNewWorldTransform(*planning_scene_state_, 01086 req.motion_plan_request.goal_constraints); 01087 01088 collision_models_->convertConstraintsGivenNewWorldTransform(*planning_scene_state_, 01089 req.motion_plan_request.path_constraints); 01090 01091 //overwriting start state - move arm only deals with current state state 01092 planning_environment::convertKinematicStateToRobotState(*planning_scene_state_, 01093 ros::Time::now(), 01094 collision_models_->getWorldFrameId(), 01095 req.motion_plan_request.start_state); 01096 original_request_ = req; 01097 01098 ros::Rate move_arm_rate(move_arm_frequency_); 01099 move_arm_action_result_.contacts.clear(); 01100 move_arm_action_result_.error_code.val = 0; 01101 move_arm_stats_.time_to_execution = ros::Time::now().toSec(); 01102 move_arm_stats_.time_to_result = ros::Time::now().toSec(); 01103 while(private_handle_.ok()) 01104 { 01105 if (action_server_->isPreemptRequested()) 01106 { 01107 revertPlanningScene(); 01108 move_arm_stats_.preempted = true; 01109 if(publish_stats_) 01110 publishStats(); 01111 move_arm_stats_.time_to_execution = ros::Time::now().toSec(); 01112 move_arm_stats_.time_to_result = ros::Time::now().toSec(); 01113 if(action_server_->isNewGoalAvailable()) 01114 { 01115 move_arm_action_result_.contacts.clear(); 01116 move_arm_action_result_.error_code.val = 0; 01117 const arm_navigation_msgs::MoveArmGoalConstPtr& new_goal = action_server_->acceptNewGoal(); 01118 moveArmGoalToPlannerRequest(new_goal,req); 01119 ROS_DEBUG("Received new goal, will preempt previous goal"); 01120 if(!getAndSetPlanningScene(new_goal->planning_scene_diff, new_goal->operations)) { 01121 ROS_INFO("Problem setting planning scene"); 01122 move_arm_action_result_.error_code.val = move_arm_action_result_.error_code.INCOMPLETE_ROBOT_STATE; 01123 action_server_->setAborted(move_arm_action_result_); 01124 return; 01125 } 01126 01127 collision_models_->convertConstraintsGivenNewWorldTransform(*planning_scene_state_, 01128 req.motion_plan_request.goal_constraints); 01129 01130 collision_models_->convertConstraintsGivenNewWorldTransform(*planning_scene_state_, 01131 req.motion_plan_request.path_constraints); 01132 planning_environment::convertKinematicStateToRobotState(*planning_scene_state_, 01133 ros::Time::now(), 01134 collision_models_->getWorldFrameId(), 01135 req.motion_plan_request.start_state); 01136 original_request_ = req; 01137 01138 state_ = PLANNING; 01139 } 01140 else //if we've been preempted explicitly we need to shut things down 01141 { 01142 ROS_DEBUG("The move arm action was preempted by the action client. Preempting this goal."); 01143 revertPlanningScene(); 01144 resetStateMachine(); 01145 action_server_->setPreempted(); 01146 return; 01147 } 01148 } 01149 01150 //for timing that gives real time even in simulation 01151 ros::WallTime start = ros::WallTime::now(); 01152 01153 //the real work on pursuing a goal is done here 01154 bool done = executeCycle(req); 01155 01156 01157 if(done) 01158 { 01159 if(publish_stats_) 01160 publishStats(); 01161 return; 01162 } 01163 01164 ros::WallDuration t_diff = ros::WallTime::now() - start; 01165 ROS_DEBUG("Full control cycle time: %.9f\n", t_diff.toSec()); 01166 01167 move_arm_rate.sleep(); 01168 } 01169 //if the node is killed then we'll abort and return 01170 ROS_INFO("Node was killed, aborting"); 01171 action_server_->setAborted(move_arm_action_result_); 01172 } 01173 01174 bool getAndSetPlanningScene(const arm_navigation_msgs::PlanningScene& planning_diff, 01175 const arm_navigation_msgs::OrderedCollisionOperations& operations) { 01176 arm_navigation_msgs::SetPlanningSceneDiff::Request planning_scene_req; 01177 arm_navigation_msgs::SetPlanningSceneDiff::Response planning_scene_res; 01178 01179 revertPlanningScene(); 01180 01181 planning_scene_req.planning_scene_diff = planning_diff; 01182 planning_scene_req.operations = operations; 01183 01184 if(!set_planning_scene_diff_client_.call(planning_scene_req, planning_scene_res)) { 01185 ROS_WARN("Can't get planning scene"); 01186 return false; 01187 } 01188 01189 current_planning_scene_ = planning_scene_res.planning_scene; 01190 01191 planning_scene_state_ = collision_models_->setPlanningScene(current_planning_scene_); 01192 01193 collision_models_->disableCollisionsForNonUpdatedLinks(group_); 01194 01195 if(planning_scene_state_ == NULL) { 01196 ROS_WARN("Problems setting local state"); 01197 return false; 01198 } 01199 return true; 01200 } 01201 01202 void resetToStartState(planning_models::KinematicState* state) { 01203 planning_environment::setRobotStateAndComputeTransforms(current_planning_scene_.robot_state, *state); 01204 } 01205 01206 bool revertPlanningScene() { 01207 if(planning_scene_state_ != NULL) { 01208 collision_models_->revertPlanningScene(planning_scene_state_); 01209 planning_scene_state_ = NULL; 01210 } 01211 return true; 01212 } 01213 01217 01221 void publishStats() 01222 { 01223 move_arm_stats_.error_code.val = move_arm_action_result_.error_code.val; 01224 move_arm_stats_.result = arm_navigation_msgs::armNavigationErrorCodeToString(move_arm_action_result_.error_code); 01225 stats_publisher_.publish(move_arm_stats_); 01226 // Reset 01227 move_arm_stats_.error_code.val = 0; 01228 move_arm_stats_.result = " "; 01229 move_arm_stats_.request_id++; 01230 move_arm_stats_.planning_time = -1.0; 01231 move_arm_stats_.smoothing_time = -1.0; 01232 move_arm_stats_.ik_time = -1.0; 01233 move_arm_stats_.time_to_execution = -1.0; 01234 move_arm_stats_.time_to_result = -1.0; 01235 move_arm_stats_.preempted = false; 01236 move_arm_stats_.num_replans = 0.0; 01237 move_arm_stats_.trajectory_duration = -1.0; 01238 } 01239 01240 void printTrajectory(const trajectory_msgs::JointTrajectory &trajectory) 01241 { 01242 for (unsigned int i = 0 ; i < trajectory.points.size() ; ++i) 01243 { 01244 std::stringstream ss; 01245 for (unsigned int j = 0 ; j < trajectory.points[i].positions.size() ; ++j) 01246 ss << trajectory.points[i].positions[j] << " "; 01247 ss << trajectory.points[i].time_from_start.toSec(); 01248 ROS_DEBUG("%s", ss.str().c_str()); 01249 } 01250 } 01251 void visualizeJointGoal(arm_navigation_msgs::GetMotionPlan::Request &req) 01252 { 01253 //if(!isJointGoal(req)) 01254 //{ 01255 // ROS_WARN("Only joint goals can be displayed"); 01256 // return; 01257 //} 01258 ROS_DEBUG("Displaying joint goal"); 01259 arm_navigation_msgs::DisplayTrajectory d_path; 01260 d_path.model_id = req.motion_plan_request.group_name; 01261 d_path.trajectory.joint_trajectory = arm_navigation_msgs::jointConstraintsToJointTrajectory(req.motion_plan_request.goal_constraints.joint_constraints); 01262 resetToStartState(planning_scene_state_); 01263 planning_environment::convertKinematicStateToRobotState(*planning_scene_state_, 01264 ros::Time::now(), 01265 collision_models_->getWorldFrameId(), 01266 d_path.robot_state); 01267 display_joint_goal_publisher_.publish(d_path); 01268 ROS_DEBUG("Displaying move arm joint goal."); 01269 } 01270 void visualizeJointGoal(const trajectory_msgs::JointTrajectory &trajectory) 01271 { 01272 ROS_DEBUG("Displaying joint goal"); 01273 arm_navigation_msgs::DisplayTrajectory d_path; 01274 d_path.trajectory.joint_trajectory = trajectory; 01275 resetToStartState(planning_scene_state_); 01276 planning_environment::convertKinematicStateToRobotState(*planning_scene_state_, 01277 ros::Time::now(), 01278 collision_models_->getWorldFrameId(), 01279 d_path.robot_state); 01280 display_joint_goal_publisher_.publish(d_path); 01281 } 01282 void visualizePlan(const trajectory_msgs::JointTrajectory &trajectory) 01283 { 01284 move_arm_action_feedback_.state = "visualizing plan"; 01285 if(action_server_->isActive()) 01286 action_server_->publishFeedback(move_arm_action_feedback_); 01287 arm_navigation_msgs::DisplayTrajectory d_path; 01288 d_path.model_id = original_request_.motion_plan_request.group_name; 01289 d_path.trajectory.joint_trajectory = trajectory; 01290 resetToStartState(planning_scene_state_); 01291 planning_environment::convertKinematicStateToRobotState(*planning_scene_state_, 01292 ros::Time::now(), 01293 collision_models_->getWorldFrameId(), 01294 d_path.robot_state); 01295 display_path_publisher_.publish(d_path); 01296 } 01297 void visualizeAllowedContactRegions(const std::vector<arm_navigation_msgs::AllowedContactSpecification> &allowed_contacts) 01298 { 01299 static int count = 0; 01300 visualization_msgs::MarkerArray mk; 01301 mk.markers.resize(allowed_contacts.size()); 01302 for(unsigned int i=0; i < allowed_contacts.size(); i++) 01303 { 01304 bool valid_shape = true; 01305 mk.markers[i].header.stamp = ros::Time::now(); 01306 mk.markers[i].header.frame_id = allowed_contacts[i].pose_stamped.header.frame_id; 01307 mk.markers[i].ns = "move_arm::"+allowed_contacts[i].name; 01308 mk.markers[i].id = count++; 01309 if(allowed_contacts[i].shape.type == arm_navigation_msgs::Shape::SPHERE) 01310 { 01311 mk.markers[i].type = visualization_msgs::Marker::SPHERE; 01312 if(allowed_contacts[i].shape.dimensions.size() >= 1) 01313 mk.markers[i].scale.x = mk.markers[i].scale.y = mk.markers[i].scale.z = allowed_contacts[i].shape.dimensions[0]; 01314 else 01315 valid_shape = false; 01316 } 01317 else if (allowed_contacts[i].shape.type == arm_navigation_msgs::Shape::BOX) 01318 { 01319 mk.markers[i].type = visualization_msgs::Marker::CUBE; 01320 if(allowed_contacts[i].shape.dimensions.size() >= 3) 01321 { 01322 mk.markers[i].scale.x = allowed_contacts[i].shape.dimensions[0]; 01323 mk.markers[i].scale.y = allowed_contacts[i].shape.dimensions[1]; 01324 mk.markers[i].scale.z = allowed_contacts[i].shape.dimensions[2]; 01325 } 01326 else 01327 valid_shape = false; 01328 } 01329 else if (allowed_contacts[i].shape.type == arm_navigation_msgs::Shape::CYLINDER) 01330 { 01331 mk.markers[i].type = visualization_msgs::Marker::CYLINDER; 01332 if(allowed_contacts[i].shape.dimensions.size() >= 2) 01333 { 01334 mk.markers[i].scale.x = allowed_contacts[i].shape.dimensions[0]; 01335 mk.markers[i].scale.y = allowed_contacts[i].shape.dimensions[0]; 01336 mk.markers[i].scale.z = allowed_contacts[i].shape.dimensions[1]; 01337 } 01338 else 01339 valid_shape = false; 01340 } 01341 else 01342 { 01343 mk.markers[i].scale.x = mk.markers[i].scale.y = mk.markers[i].scale.z = 0.01; 01344 valid_shape = false; 01345 } 01346 01347 mk.markers[i].action = visualization_msgs::Marker::ADD; 01348 mk.markers[i].pose = allowed_contacts[i].pose_stamped.pose; 01349 if(!valid_shape) 01350 { 01351 mk.markers[i].scale.x = mk.markers[i].scale.y = mk.markers[i].scale.z = 0.01; 01352 mk.markers[i].color.a = 0.3; 01353 mk.markers[i].color.r = 1.0; 01354 mk.markers[i].color.g = 0.04; 01355 mk.markers[i].color.b = 0.04; 01356 } 01357 else 01358 { 01359 mk.markers[i].color.a = 1.0; 01360 mk.markers[i].color.r = 0.04; 01361 mk.markers[i].color.g = 1.0; 01362 mk.markers[i].color.b = 0.04; 01363 } 01364 //mk.markers[i].lifetime = ros::Duration(30.0); 01365 } 01366 allowed_contact_regions_publisher_.publish(mk); 01367 } 01371 01372 private: 01373 01374 std::string group_; 01375 01376 ros::ServiceClient ik_client_; 01377 ros::ServiceClient trajectory_start_client_,trajectory_cancel_client_,trajectory_query_client_; 01378 ros::NodeHandle private_handle_, root_handle_; 01379 boost::shared_ptr<actionlib::SimpleActionServer<arm_navigation_msgs::MoveArmAction> > action_server_; 01380 01381 planning_environment::CollisionModels* collision_models_; 01382 01383 arm_navigation_msgs::SetPlanningSceneDiff::Request set_planning_scene_diff_req_; 01384 arm_navigation_msgs::SetPlanningSceneDiff::Response set_planning_scene_diff_res_; 01385 arm_navigation_msgs::PlanningScene current_planning_scene_; 01386 planning_models::KinematicState* planning_scene_state_; 01387 01388 tf::TransformListener *tf_; 01389 MoveArmState state_; 01390 double move_arm_frequency_; 01391 trajectory_msgs::JointTrajectory current_trajectory_; 01392 01393 int num_planning_attempts_; 01394 01395 std::vector<std::string> group_joint_names_; 01396 std::vector<std::string> group_link_names_; 01397 std::vector<std::string> all_link_names_; 01398 arm_navigation_msgs::MoveArmResult move_arm_action_result_; 01399 arm_navigation_msgs::MoveArmFeedback move_arm_action_feedback_; 01400 01401 arm_navigation_msgs::GetMotionPlan::Request original_request_; 01402 01403 ros::Publisher display_path_publisher_; 01404 ros::Publisher display_joint_goal_publisher_; 01405 ros::Publisher allowed_contact_regions_publisher_; 01406 ros::Publisher vis_marker_publisher_; 01407 ros::Publisher vis_marker_array_publisher_; 01408 ros::ServiceClient filter_trajectory_client_; 01409 ros::ServiceClient get_state_client_; 01410 ros::ServiceClient set_planning_scene_diff_client_; 01411 MoveArmParameters move_arm_parameters_; 01412 01413 ControllerStatus controller_status_; 01414 01415 JointExecutorActionClient* controller_action_client_; 01416 JointExecutorActionClient::GoalHandle controller_goal_handle_; 01417 01418 double trajectory_filter_allowed_time_, ik_allowed_time_; 01419 double trajectory_discretization_; 01420 bool arm_ik_initialized_; 01421 01422 bool publish_stats_; 01423 arm_navigation_msgs::MoveArmStatistics move_arm_stats_; 01424 ros::Publisher stats_publisher_; 01425 01426 }; 01427 } 01428 01429 int main(int argc, char** argv) 01430 { 01431 ros::init(argc, argv, "move_arm"); 01432 01433 ros::AsyncSpinner spinner(1); // Use 1 thread 01434 spinner.start(); 01435 ros::NodeHandle nh("~"); 01436 std::string group; 01437 nh.param<std::string>("group", group, std::string()); 01438 ROS_INFO("Move arm operating on group %s",group.c_str()); 01439 move_arm::MoveArm move_arm(group); 01440 if(!move_arm.configure()) 01441 { 01442 ROS_ERROR("Could not configure move arm, exiting"); 01443 ros::shutdown(); 01444 return 1; 01445 } 01446 ROS_INFO("Move arm action started"); 01447 ros::waitForShutdown(); 01448 01449 return 0; 01450 }