ik_trajectory_tutorial.cpp
Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <time.h>
00004 #include <ros/ros.h>
00005 #include <pr2_controllers_msgs/JointTrajectoryAction.h>
00006 #include <pr2_controllers_msgs/JointTrajectoryControllerState.h>
00007 #include <actionlib/client/simple_action_client.h>
00008 #include <kinematics_msgs/GetPositionIK.h>
00009 #include <kinematics_msgs/GetPositionFK.h>
00010 #include <pr2_laban_gazebo_demo/ExecuteCartesianIKTrajectory.h>
00011 #include <vector>
00012 
00013 #define MAX_JOINT_VEL 0.5  //in radians/sec
00014 
00015 static const std::string ARM_IK_NAME = "/pr2_right_arm_kinematics/get_ik";
00016 typedef actionlib::SimpleActionClient<pr2_controllers_msgs::
00017                                       JointTrajectoryAction> TrajClient;
00018 
00019 class IKTrajectoryExecutor{
00020 
00021 private:
00022   ros::NodeHandle node;
00023   ros::ServiceClient ik_client;
00024   ros::ServiceServer service;
00025   pr2_controllers_msgs::JointTrajectoryGoal goal;
00026   kinematics_msgs::GetPositionIK::Request  ik_request;
00027   kinematics_msgs::GetPositionIK::Response ik_response;  
00028   TrajClient *action_client;
00029 
00030 public:
00031   IKTrajectoryExecutor(){
00032 
00033     //create a client function for the IK service
00034     ik_client = node.serviceClient<kinematics_msgs::GetPositionIK>
00035       (ARM_IK_NAME, true);    
00036 
00037     //wait for the various services to be ready
00038     ROS_INFO("Waiting for services to be ready");
00039     ros::service::waitForService(ARM_IK_NAME);
00040     ROS_INFO("Services ready");
00041 
00042     //tell the joint trajectory action client that we want 
00043     //to spin a thread by default
00044     action_client = new TrajClient("r_arm_controller/joint_trajectory_action", true);
00045 
00046     //wait for the action server to come up
00047     while(ros::ok() && !action_client->waitForServer(ros::Duration(5.0))){
00048       ROS_INFO("Waiting for the joint_trajectory_action action server to come up");
00049     }
00050 
00051     //register a service to input desired Cartesian trajectories
00052     service = node.advertiseService("execute_cartesian_ik_trajectory", 
00053         &IKTrajectoryExecutor::execute_cartesian_ik_trajectory, this);
00054 
00055     //have to specify the order of the joints we're sending in our 
00056     //joint trajectory goal, even if they're already on the param server
00057     goal.trajectory.joint_names.push_back("r_shoulder_pan_joint");
00058     goal.trajectory.joint_names.push_back("r_shoulder_lift_joint");
00059     goal.trajectory.joint_names.push_back("r_upper_arm_roll_joint");
00060     goal.trajectory.joint_names.push_back("r_elbow_flex_joint");
00061     goal.trajectory.joint_names.push_back("r_forearm_roll_joint");
00062     goal.trajectory.joint_names.push_back("r_wrist_flex_joint");
00063     goal.trajectory.joint_names.push_back("r_wrist_roll_joint");
00064 
00065   }
00066 
00067   ~IKTrajectoryExecutor(){
00068     delete action_client;
00069   }
00070 
00071 
00072   //run inverse kinematics on a PoseStamped (7-dof pose 
00073   //(position + quaternion orientation) + header specifying the 
00074   //frame of the pose)
00075   //tries to stay close to double start_angles[7]
00076   //returns the solution angles in double solution[7] 
00077   bool run_ik(geometry_msgs::PoseStamped pose, double start_angles[7], 
00078               double solution[7], std::string link_name){
00079 
00080     kinematics_msgs::GetPositionIK::Request  ik_request;
00081     kinematics_msgs::GetPositionIK::Response ik_response;  
00082  
00083     ik_request.timeout = ros::Duration(5.0);
00084 ik_request.ik_request.ik_seed_state.joint_state.name.push_back("r_shoulder_pan_joint");
00085     ik_request.ik_request.ik_seed_state.joint_state.name.push_back("r_shoulder_lift_joint");
00086     ik_request.ik_request.ik_seed_state.joint_state.name.push_back("r_upper_arm_roll_joint");
00087     ik_request.ik_request.ik_seed_state.joint_state.name.push_back("r_elbow_flex_joint");
00088     ik_request.ik_request.ik_seed_state.joint_state.name.push_back("r_forearm_roll_joint");
00089     ik_request.ik_request.ik_seed_state.joint_state.name.push_back("r_wrist_flex_joint");
00090     ik_request.ik_request.ik_seed_state.joint_state.name.push_back("r_wrist_roll_joint");
00091 
00092     ik_request.ik_request.ik_link_name = link_name; 
00093 
00094     ik_request.ik_request.pose_stamped = pose;
00095     ik_request.ik_request.ik_seed_state.joint_state.position.resize(7);
00096 
00097     for(int i=0; i<7; i++) ik_request.ik_request.ik_seed_state.joint_state.position[i] = start_angles[i];
00098 
00099     ROS_INFO("request pose: %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f", pose.pose.position.x, pose.pose.position.y, pose.pose.position.z, pose.pose.orientation.x, pose.pose.orientation.y, pose.pose.orientation.z, pose.pose.orientation.w);
00100 
00101     bool ik_service_call = ik_client.call(ik_request,ik_response);
00102     if(!ik_service_call){
00103       ROS_ERROR("IK service call failed!");  
00104       return 0;
00105     }
00106     if(ik_response.error_code.val == ik_response.error_code.SUCCESS){
00107       for(int i=0; i<7; i++){
00108         solution[i] = ik_response.solution.joint_state.position[i];
00109       }
00110       ROS_INFO("solution angles: %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f", 
00111              solution[0],solution[1], solution[2],solution[3],
00112              solution[4],solution[5],solution[6]);
00113       ROS_INFO("IK service call succeeded");
00114       return 1;
00115     }
00116     ROS_INFO("IK service call error code: %d", ik_response.error_code.val);
00117     return 0;
00118   }
00119 
00120 
00121   //figure out where the arm is now  
00122   void get_current_joint_angles(double current_angles[7]){
00123     int i;
00124 
00125     //get a single message from the topic 'r_arm_controller/state'
00126     pr2_controllers_msgs::JointTrajectoryControllerStateConstPtr state_msg = 
00127       ros::topic::waitForMessage<pr2_controllers_msgs::JointTrajectoryControllerState>
00128       ("r_arm_controller/state");
00129     
00130     //extract the joint angles from it
00131     for(i=0; i<7; i++){
00132       current_angles[i] = state_msg->actual.positions[i];
00133     }
00134   }
00135 
00136 
00137   //send a desired joint trajectory to the joint trajectory action
00138   //and wait for it to finish
00139   bool execute_joint_trajectory(std::vector<double *> joint_trajectory){
00140     int i, j; 
00141     int trajectorylength = joint_trajectory.size();
00142 
00143     //get the current joint angles
00144     double current_angles[7];    
00145     get_current_joint_angles(current_angles);
00146 
00147     //fill the goal message with the desired joint trajectory
00148     goal.trajectory.points.resize(trajectorylength+1);
00149 
00150     //set the first trajectory point to the current position
00151     goal.trajectory.points[0].positions.resize(7);
00152     goal.trajectory.points[0].velocities.resize(7);
00153     for(j=0; j<7; j++){
00154       goal.trajectory.points[0].positions[j] = current_angles[j];
00155       goal.trajectory.points[0].velocities[j] = 0.0; 
00156     }
00157 
00158     //make the first trajectory point start 0.25 seconds from when we run
00159     goal.trajectory.points[0].time_from_start = ros::Duration(0.25);     
00160 
00161     //fill in the rest of the trajectory
00162     double time_from_start = 0.25;
00163     for(i=0; i<trajectorylength; i++){
00164       goal.trajectory.points[i+1].positions.resize(7);
00165       goal.trajectory.points[i+1].velocities.resize(7);
00166 
00167       //fill in the joint positions (velocities of 0 mean that the arm
00168       //will try to stop briefly at each waypoint)
00169       for(j=0; j<7; j++){
00170         goal.trajectory.points[i+1].positions[j] = joint_trajectory[i][j];
00171         goal.trajectory.points[i+1].velocities[j] = 0.0;
00172       }
00173 
00174       //compute a desired time for this trajectory point using a max 
00175       //joint velocity
00176       double max_joint_move = 0;
00177       for(j=0; j<7; j++){
00178         double joint_move = fabs(goal.trajectory.points[i+1].positions[j] 
00179                                  - goal.trajectory.points[i].positions[j]);
00180         if(joint_move > max_joint_move) max_joint_move = joint_move;
00181       }
00182       double seconds = max_joint_move/MAX_JOINT_VEL;
00183       ROS_INFO("max_joint_move: %0.3f, seconds: %0.3f", max_joint_move, seconds);
00184       time_from_start += seconds;
00185       goal.trajectory.points[i+1].time_from_start = 
00186         ros::Duration(time_from_start);
00187     }
00188 
00189     //when to start the trajectory
00190     goal.trajectory.header.stamp = ros::Time::now() + ros::Duration(0.25);
00191 
00192     ROS_INFO("Sending goal to joint_trajectory_action");
00193     action_client->sendGoal(goal);
00194 
00195     action_client->waitForResult();
00196 
00197     //get the current joint angles for debugging
00198     get_current_joint_angles(current_angles);
00199     ROS_INFO("joint angles after trajectory: %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f\n",current_angles[0],current_angles[1],current_angles[2],current_angles[3],current_angles[4],current_angles[5],current_angles[6]);
00200 
00201     if(action_client->getState() == actionlib::SimpleClientGoalState::SUCCEEDED){
00202       ROS_INFO("Hooray, the arm finished the trajectory!");
00203       return 1;
00204     }
00205     ROS_INFO("The arm failed to execute the trajectory.");
00206     return 0;
00207   }
00208 
00209 
00210   //service function for execute_cartesian_ik_trajectory
00211   bool execute_cartesian_ik_trajectory(
00212          pr2_laban_gazebo_demo::ExecuteCartesianIKTrajectory::Request &req,
00213          pr2_laban_gazebo_demo::ExecuteCartesianIKTrajectory::Response &res){
00214 
00215     int trajectory_length = req.poses.size();
00216     int i, j;
00217     
00218     //IK takes in Cartesian poses stamped with the frame they belong to
00219     geometry_msgs::PoseStamped stamped_pose;
00220     stamped_pose.header = req.header;
00221     stamped_pose.header.stamp = ros::Time::now();
00222     bool success;
00223     std::vector<double *> joint_trajectory;
00224 
00225     //get the current joint angles (to find ik solutions close to)
00226     double last_angles[7];    
00227     get_current_joint_angles(last_angles);
00228 
00229     //find IK solutions for each point along the trajectory 
00230     //and stick them into joint_trajectory
00231     for(i=0; i<trajectory_length; i++){
00232       
00233       stamped_pose.pose = req.poses[i];
00234       double *trajectory_point = new double[7];
00235       success = run_ik(stamped_pose, last_angles, trajectory_point, "r_wrist_roll_link");
00236       joint_trajectory.push_back(trajectory_point);
00237 
00238       if(!success){
00239         ROS_ERROR("IK solution not found for trajectory point number %d!\n", i);
00240         return 0;
00241       }
00242       for(j=0; j<7; j++) last_angles[j] = trajectory_point[j];
00243     }        
00244 
00245     //run the resulting joint trajectory
00246     ROS_INFO("executing joint trajectory");
00247     success = execute_joint_trajectory(joint_trajectory);
00248     res.success = success;
00249     
00250     return success;
00251   }
00252 
00253 };
00254 
00255 
00256 int main(int argc, char** argv){
00257 
00258   //init ROS node
00259   ros::init(argc, argv, "cartesian_ik_trajectory_executor");
00260 
00261   IKTrajectoryExecutor ik_traj_exec = IKTrajectoryExecutor();
00262 
00263   ROS_INFO("Waiting for cartesian trajectories to execute");
00264   ros::spin();
00265   
00266   return 0;
00267 }
00268 


pr2_laban_gazebo_demo
Author(s): John Hsu
autogenerated on Mon Jan 6 2014 12:03:25