RobotTrajectoryExecutor.cpp
Go to the documentation of this file.
00001 #include <moveit_controller_multidof/RobotTrajectoryExecutor.h>
00002 #include <moveit_controller_multidof/PathConverter.h>
00003 
00004 // send robot path navigation and jaco arm trajectory in paralllel. If false, the path will be executed first.
00005 #define SEND_TRAJECTORIES_PARALLEL true
00006 
00007 using namespace moveit_controller_multidof;
00008 
00009 RobotTrajectoryExecutor::RobotTrajectoryExecutor(const std::string& _virtual_joint_name,
00010         const std::string _trajectory_action_topic, const std::string _path_action_topic) : 
00011     trajectory_action_topic(_trajectory_action_topic),
00012     path_action_topic(_path_action_topic),
00013     joint_trajectory_action_client(NULL),
00014     path_navigation_action_client(NULL),
00015     has_path_navigator(false), 
00016     has_current_request(false),
00017     has_current_trajectory(false),
00018     last_exec(SUCCEEDED),
00019     virtual_joint_name(_virtual_joint_name),
00020     path_running(false),
00021     trajectory_running(false)
00022  {
00023 
00024     ROS_INFO_STREAM("Loading RobotTrajectoryExecutor");
00025 
00026 /*
00027     ros::NodeHandle node("~");
00028     
00029     node.param<std::string>("joint_trajectory_action_topic", trajectory_action_topic, DEFAULT_trajectory_action_topic);
00030     ROS_INFO("Got joint trajectory action topic name: <%s>", trajectory_action_topic.c_str());
00031     
00032     node.param<std::string>("path_navigation_action_topic", path_action_topic, "");
00033     ROS_INFO("Got path navigation action topic name: <%s>", path_action_topic.c_str());
00034   */
00035   
00036     has_path_navigator=(!virtual_joint_name.empty() && !path_action_topic.empty());
00037 
00038     if (virtual_joint_name.empty() != path_action_topic.empty())
00039     {
00040         ROS_WARN_STREAM("Specified either virtual joint or path action topic. "
00041             <<"But path navigation is not enabled unless both are set: "
00042             <<"Virtual joint name: "<<virtual_joint_name<<", path action topic: "<<path_action_topic);
00043     }
00044 
00045     if (!trajectory_action_topic.empty()) joint_trajectory_action_client = new FollowJointTrajectoryActionClient(trajectory_action_topic, true);
00046     if (has_path_navigator) path_navigation_action_client = new PathNavigationActionClient(path_action_topic, true);
00047 
00048     if (trajectory_action_topic.empty() && path_action_topic.empty())
00049     {
00050         ROS_ERROR("RobotTrajectoryExecutor: Both trajectory and path action topics are empty, so RobotTrajectoryExecutor will not do anything");
00051     }
00052     /*if (!connectClients()) {
00053         ROS_ERROR("Not all clients connected");
00054     }*/
00055 
00056     ROS_INFO("RobotTrajectoryExecutor ready to go");
00057 }
00058 
00059 
00060 RobotTrajectoryExecutor::RobotTrajectoryExecutor(const RobotTrajectoryExecutor& other):
00061     trajectory_action_topic(other.trajectory_action_topic),
00062     path_action_topic(other.trajectory_action_topic),
00063     has_path_navigator(other.has_path_navigator), 
00064     has_current_request(other.has_current_request),
00065     has_current_trajectory(other.has_current_trajectory),
00066     last_exec(other.last_exec),
00067     virtual_joint_name(other.virtual_joint_name),
00068     current_trajectory(other.current_trajectory),
00069     path_running(other.path_running),
00070     trajectory_running(other.trajectory_running) {
00071     
00072     ROS_WARN("Using copy constructor of RobotTrajectoryExecutor");
00073     if (!trajectory_action_topic.empty()) joint_trajectory_action_client = new FollowJointTrajectoryActionClient(trajectory_action_topic, true);
00074     else joint_trajectory_action_client=NULL;
00075 
00076     if (has_path_navigator) path_navigation_action_client = new PathNavigationActionClient(path_action_topic, true);
00077     else path_navigation_action_client=NULL;
00078 
00079     /*if (!connectClients()) {
00080         ROS_ERROR("Not all clients connected");
00081     }*/
00082 } 
00083 
00084 
00085 RobotTrajectoryExecutor::~RobotTrajectoryExecutor(){
00086     if (joint_trajectory_action_client) delete joint_trajectory_action_client;
00087     if (path_navigation_action_client) delete path_navigation_action_client;
00088 }
00089 
00090 
00091 bool RobotTrajectoryExecutor::hasTrajectoryServer() const
00092 {
00093     return !trajectory_action_topic.empty() && (joint_trajectory_action_client!=NULL);
00094 }
00095 
00096 bool RobotTrajectoryExecutor::sendTrajectory(const moveit_msgs::RobotTrajectory &t)
00097 {
00098     ROS_INFO("RobotTrajectoryExecutor: Received RobotTrajectory.");
00099     //ROS_INFO_STREAM(t);
00100 
00101     if (!clientsConnected()) {
00102         bool ret=connectClients();
00103         if (!connectClients()) {
00104             ROS_ERROR("RobotTrajecoryExecutor: Failed to connect to clients, hence can't execute RobotTrajectory");
00105             return false;
00106         }
00107     } 
00108 
00109     current_trajectory=t.joint_trajectory;
00110 
00111     bool execPathFirst=false;
00112 
00113     if (!t.multi_dof_joint_trajectory.points.empty())
00114     {
00115         ROS_INFO_STREAM("Getting trajectory "<<t.multi_dof_joint_trajectory);
00116 
00117         if (t.multi_dof_joint_trajectory.joint_names.size()!=1) {
00118             ROS_ERROR("Support only multiDOF joint trajectory of 1 joint, namely the virtual joint (of name %s)",
00119                 virtual_joint_name.c_str());
00120             return false;
00121         }
00122         if (t.multi_dof_joint_trajectory.joint_names[0]!=virtual_joint_name) {
00123             ROS_ERROR("Support only multiDOF joint trajectory of virtual joint '%s', but got it for joint %s",
00124                 virtual_joint_name.c_str(),t.multi_dof_joint_trajectory.joint_names[0].c_str());
00125             return false;
00126         }
00127     
00128         ROS_INFO("Got a joint trajectory of size %zu for virtual joint '%s'. NOTE: velocities and accellerations are not supported yet. File %s.",
00129             t.multi_dof_joint_trajectory.points.size(),virtual_joint_name.c_str(),__FILE__);    
00130 
00131         std::vector<geometry_msgs::Transform> transforms;
00132         std::vector<ros::Duration> times;
00133         for (int i=0; i<t.multi_dof_joint_trajectory.points.size(); ++i) {
00134             
00135             const std::vector<geometry_msgs::Transform>& transforms_=t.multi_dof_joint_trajectory.points[i].transforms; 
00136             if (transforms_.size()!=1) {
00137                 ROS_ERROR("Consistency: Must have same number of transforms as joints, i.e. only 1 for the virtual joint");
00138             }
00139 
00140             geometry_msgs::Transform tr=transforms_[0];
00141         
00142             //ROS_INFO("Navigation to %f %f %f (quaternion %f %f %f)",tr.translation.x,tr.translation.y,tr.translation.z,
00143             //    tr.rotation.x,tr.rotation.y,tr.rotation.z);
00144             //ROS_INFO_STREAM("Time: "<<t.multi_dof_joint_trajectory.points[i].time_from_start);
00145             
00146             transforms.push_back(tr);    
00147             times.push_back(t.multi_dof_joint_trajectory.points[i].time_from_start);    
00148         }
00149 
00150     
00151         ROS_INFO("RobotTrajectoryExecutor: Sending navigation action request");
00152         //frame_id should be t.multi_dof_joint_trajectory.header.frame_id, but this is usually empty, so use the joint trajectories 
00153         if (!sendNavigationActionRequest(transforms,t.joint_trajectory.header.frame_id,-1,times)) {
00154             ROS_ERROR("could not send navigation request");
00155             return false;
00156         }
00157         execPathFirst=true;    
00158                 
00159     }
00160 
00161 
00162     /*for (int i=0; i<t.joint_trajectory.points.size(); ++i) {
00163         ROS_INFO_STREAM("Joint trajectory point "<<i<<", time from start "<<t.joint_trajectory.points[i].time_from_start);
00164     }*/
00165 
00166     lock.lock();
00167     has_current_request=true;
00168     has_current_trajectory=!t.joint_trajectory.joint_names.empty();
00169     lock.unlock();
00170 
00171     last_exec = RUNNING;
00172 
00173     // send a goal to the action directly, as there is no path to be executed first
00174     if (SEND_TRAJECTORIES_PARALLEL || !execPathFirst)
00175     {
00176         if (!t.joint_trajectory.joint_names.empty() && !hasTrajectoryServer())
00177         {
00178             ROS_WARN("RobotTrajectoryExecutor: joint trajectory was not empty, but no joint trajectory server is configured. Joint trajectory will not be executed.");
00179         }
00180         if (hasTrajectoryServer() && !sendTrajectoryActionRequest(current_trajectory,-1))
00181         {
00182             ROS_ERROR("could not send navigation request");
00183             return false;
00184         }
00185     }
00186     return true;
00187 }
00188 
00189 
00190 bool RobotTrajectoryExecutor::cancelExecution() {     
00191     if (!clientsConnected()) {
00192         ROS_WARN("RobotTrajectoryExecutor: Canceling execution which can't have been successfully started before");
00193         return false;
00194     }
00195     
00196     lock.lock();
00197     if (has_current_request)
00198     {
00199         ROS_INFO_STREAM("RobotTrajectoryExecutor: Cancelling execution");
00200         last_exec = PREEMPTED;
00201         if (has_current_trajectory) {
00202             if (trajectory_running) joint_trajectory_action_client->cancelGoal();
00203         }
00204         if (has_path_navigator) {
00205             if (path_running) path_navigation_action_client->cancelGoal();
00206         }
00207         has_current_request = false;
00208         has_current_trajectory = false;
00209     }
00210     lock.unlock();
00211     return true;
00212 }
00213 
00214 bool RobotTrajectoryExecutor::waitForExecution(const ros::Duration & timeout)
00215 {
00216     if (!clientsConnected()) {
00217         ROS_WARN("RobotTrajectoryExecutor: Waiting for execution which can't have been successfully started before");
00218         return false;
00219     }
00220     
00221     lock.lock();
00222     bool active_request=has_current_request;
00223     bool active_path=path_running;
00224     bool active_trajectory=trajectory_running;
00225     lock.unlock();
00226 
00227     // wait for the current execution to finish
00228     if (active_request) {
00229         //XXX this has to be improved to allow cancellation of goals if parallel execution is enabled and one fails at an early stage.
00230 
00231         ROS_INFO_STREAM("RobotTrajectoryExecutor: Waiting for execution for "<<timeout<<" secs");
00232         bool pathOk=!active_path || !has_path_navigator || path_navigation_action_client->waitForResult(timeout);
00233         
00234         if (!pathOk && SEND_TRAJECTORIES_PARALLEL && active_trajectory) {
00235             joint_trajectory_action_client->cancelGoal();
00236         }
00237         if (pathOk) {
00238             bool trajOk=!active_trajectory || joint_trajectory_action_client->waitForResult(timeout);
00239             if (trajOk) {
00240                 ROS_INFO("RobotTrajectoryExecutor: Action succeeded.");
00241                 last_exec = SUCCEEDED;
00242                 return true;
00243             }
00244         }
00245         last_exec = TIMED_OUT;
00246         ROS_WARN_STREAM("RobotTrajectoryExecutor: Action timed out. Status: "<<last_exec);
00247     }
00248     return false;
00249 }
00250 
00251 
00252 void RobotTrajectoryExecutor::pathDoneCB(const actionlib::SimpleClientGoalState& state, const PathGoalResultConstPtr& result) {
00253     //ROS_INFO("Finished path in state [%s]", state.toString().c_str());
00254     
00255     setLastStateFrom(state);
00256         
00257     if (state!=actionlib::SimpleClientGoalState::SUCCEEDED) { //PENDING/ACTIVE/DONE
00258         ROS_WARN("Unsuccessful goal state detected, so not running the joint trajectory action request.");
00259         lock.lock();
00260         path_running=false;
00261         lock.unlock();
00262         return;
00263     }    
00264 
00265     //ROS_INFO_STREAM("Answer: %i"<< result->finalpose);
00266     lock.lock();
00267     bool _has_current_trajectory=has_current_trajectory;
00268     lock.unlock();
00269 
00270     if (!SEND_TRAJECTORIES_PARALLEL && _has_current_trajectory)
00271     {
00272         if (!current_trajectory.joint_names.empty() && !hasTrajectoryServer())
00273         {
00274             ROS_WARN("RobotTrajectoryExecutor: joint trajectory was not empty, but no joint trajectory server is configured. Joint trajectory will not be executed.");
00275         }
00276         if (hasTrajectoryServer() && !sendTrajectoryActionRequest(current_trajectory,-1))
00277         {
00278             ROS_ERROR("could not send navigation request");
00279         }
00280     }
00281 }
00282 
00283 
00284 void RobotTrajectoryExecutor::trajectoryDoneCB(const actionlib::SimpleClientGoalState& state,
00285     const control_msgs::FollowJointTrajectoryResultConstPtr& result)
00286 {
00287     ROS_INFO("Finished joint trajectory in state [%s]", state.toString().c_str());
00288     //we're all done, so we can set the whole request as finished    
00289     lock.lock();
00290     has_current_trajectory=false;
00291     has_current_request=false;
00292     trajectory_running=false;
00293     lock.unlock();
00294     setLastStateFrom(state);
00295 }
00296 
00297 
00298 
00299 bool RobotTrajectoryExecutor::sendTrajectoryActionRequest(const trajectory_msgs::JointTrajectory& trajectory, float waitForResult) {
00300     if (joint_trajectory_action_client && !joint_trajectory_action_client->isServerConnected()) {
00301         ROS_ERROR_STREAM("RobotTrajectoryExecutor: Joint trajectory action client not connected: " << trajectory_action_topic);
00302         return false;
00303     }
00304 
00305     if (trajectory.joint_names.empty()) {
00306         //no trajectory to execute
00307         lock.lock();
00308         has_current_trajectory=false;
00309         has_current_request=false;
00310         lock.unlock();
00311         last_exec=SUCCEEDED;
00312         return true;
00313     }
00314     
00315     ROS_INFO("RobotTrajectoryExecutor Controller: Sending trajectory goal.");
00316 
00317     TrajectoryGoal tGoal;
00318     tGoal.trajectory = trajectory;
00319 
00320     joint_trajectory_action_client->sendGoal(tGoal, boost::bind(&RobotTrajectoryExecutor::trajectoryDoneCB, this, _1,_2));
00321     lock.lock();
00322     trajectory_running=true;
00323     lock.unlock();
00324 
00325     if (waitForResult < 0) return true;
00326 
00327     //wait for the action to return
00328     bool finished_before_timeout = joint_trajectory_action_client->waitForResult(ros::Duration(waitForResult));
00329 
00330     if (finished_before_timeout)
00331     {
00332         actionlib::SimpleClientGoalState state = joint_trajectory_action_client->getState();
00333         ROS_INFO("Action finished: %s",state.toString().c_str());
00334         return true;
00335     } else {
00336         ROS_INFO_STREAM("Action did not finish before the time out. "<<joint_trajectory_action_client->getState().toString());
00337     }
00338     return false;
00339 }
00340 
00341 
00342 
00343 
00344 bool RobotTrajectoryExecutor::sendNavigationActionRequest(const std::vector<geometry_msgs::Transform>& transforms,
00345         const std::string& transforms_frame_id, const float waitForResult, 
00346         const std::vector<ros::Duration>& times) {
00347 
00348         bool transforms_are_relative=false;
00349         geometry_msgs::Pose start_pose=geometry_msgs::Pose(); //only plays a roe if transforms_are_relative=true
00350         
00351         nav_msgs::Path p;
00352         moveit_controller_multidof::TransformPathConverter::convert(transforms,p,transforms_frame_id,
00353             transforms_are_relative,start_pose,ros::Time::now(), times);
00354 
00355         ROS_INFO_STREAM("RobotTrajectoryExecutor: path after conversion: "<<p);
00356 
00357         return sendNavigationActionRequest(p,transforms_frame_id,waitForResult);    
00358 }
00359 
00360 
00361 bool RobotTrajectoryExecutor::sendNavigationActionRequest(const nav_msgs::Path& path,
00362     const std::string& path_frame_id, const float waitForResult)
00363 {
00364     if (!has_path_navigator) {
00365         ROS_ERROR("Can't execute path, there is no path navigator configured");
00366     }
00367 
00368     if (!path_navigation_action_client->isServerConnected()) {
00369         ROS_ERROR_STREAM("RobotTrajectoryExecutor: Path execution action client not connected: " << path_action_topic);
00370         return false;
00371     }
00372 
00373     if (path.poses.empty()) {
00374         ROS_ERROR("Empty path, can't send navigation request");
00375         return false;    
00376     }
00377 
00378     ROS_INFO("RobotTrajectoryExecutor: Sending path goal.");
00379     
00380     PathGoal tGoal;
00381     tGoal.path.header.frame_id=path_frame_id;
00382     tGoal.path=path;
00383     
00384     //ROS_INFO_STREAM("Goal: "<<transform_goal);
00385 
00386     path_navigation_action_client->sendGoal(tGoal, boost::bind(&RobotTrajectoryExecutor::pathDoneCB, this, _1,_2));
00387     lock.lock();
00388     path_running=true;
00389     lock.unlock();
00390 
00391     if (waitForResult < 0) return true;
00392 
00393     //wait for the action to return
00394     bool finished_before_timeout = path_navigation_action_client->waitForResult(ros::Duration(waitForResult));
00395 
00396     if (finished_before_timeout)
00397     {
00398         actionlib::SimpleClientGoalState state = path_navigation_action_client->getState();
00399         ROS_INFO("Action finished: %s",state.toString().c_str());
00400         return true;
00401     } else {
00402         ROS_INFO_STREAM("Action did not finish before the time out. "<<path_navigation_action_client->getState().toString());
00403     }
00404     return false;
00405 }
00406 
00407 
00408 RobotTrajectoryExecutor::ExecutionStatus RobotTrajectoryExecutor::getLastExecutionStatus()
00409 {
00410     return last_exec;
00411 }
00412 
00413 bool RobotTrajectoryExecutor::clientsConnected() {
00414     bool traj_ok = !hasTrajectoryServer() || joint_trajectory_action_client->isServerConnected();    
00415     bool path_connected = false;
00416     if (has_path_navigator) path_connected=path_navigation_action_client->isServerConnected();    
00417 
00418     return traj_ok && (!has_path_navigator || path_connected);
00419 }
00420 
00421 bool RobotTrajectoryExecutor::connectClients() {
00422     unsigned int attempts = 0;
00423 
00424     bool traj_ok = !hasTrajectoryServer() || joint_trajectory_action_client->isServerConnected();    
00425     bool path_connected = false;
00426     if (has_path_navigator) path_connected=path_navigation_action_client->isServerConnected();    
00427 
00428     while (ros::ok() && !traj_ok && (!has_path_navigator || !path_connected) && (++attempts < 3)){
00429 
00430         if (!traj_ok) {            
00431             ROS_INFO_STREAM("RobotTrajectoryExecutor: Waiting for " << trajectory_action_topic << " to come up");
00432             traj_ok=joint_trajectory_action_client->waitForServer(ros::Duration(2.0));
00433         }
00434 
00435         if (has_path_navigator && !path_connected) {
00436             ROS_INFO_STREAM("RobotTrajectoryExecutor: Waiting for " << path_action_topic << " to come up");
00437             path_connected=path_navigation_action_client->waitForServer(ros::Duration(2.0));
00438         }
00439     }
00440 
00441     bool ret=true;
00442     traj_ok = !hasTrajectoryServer() || joint_trajectory_action_client->isServerConnected();    
00443     if (!traj_ok) {
00444         ROS_ERROR_STREAM("RobotTrajectoryExecutor: Joint trajectory action client not connected: " << trajectory_action_topic);
00445         ret=false;
00446     }
00447     
00448     if (has_path_navigator && !path_navigation_action_client->isServerConnected()) {
00449         ROS_ERROR_STREAM("RobotTrajectoryExecutor: Path execution action client not connected: " << path_action_topic);
00450         ret=false;
00451     }
00452     return ret;
00453 }
00454 
00455 
00456 
00457 
00458 void RobotTrajectoryExecutor::setLastStateFrom(const actionlib::SimpleClientGoalState& state) {
00459     if (state==actionlib::SimpleClientGoalState::SUCCEEDED) last_exec = SUCCEEDED;
00460     else if (state==actionlib::SimpleClientGoalState::ACTIVE) last_exec=RUNNING;
00461     else if (state==actionlib::SimpleClientGoalState::PREEMPTED) last_exec=PREEMPTED;
00462     else if (state==actionlib::SimpleClientGoalState::ABORTED) last_exec=ABORTED;
00463     else last_exec=UNKNOWN;
00464 }
00465 
00466 
00467 


moveit_controller_multidof
Author(s): Jennifer Buehler
autogenerated on Sat Mar 2 2019 03:50:48