actionlib_controller.h
Go to the documentation of this file.
00001 // Copyright (C) 2006-2009 Rosen Diankov (rdiankov@cs.cmu.edu)
00002 //
00003 // This file is part of OpenRAVE.
00004 // OpenRAVE is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU Lesser General Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU Lesser General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU Lesser General Public License
00015 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 #ifndef OPENRAVE_ACTIONLIB_H
00017 #define OPENRAVE_ACTIONLIB_H
00018 
00019 #include <rave/rave.h> // declare first
00020 
00021 #include <cstdio>
00022 #include <cstdlib>
00023 #include <string>
00024 #include <set>
00025 #include <vector>
00026 #include <boost/scoped_ptr.hpp>
00027 #include <ros/node_handle.h>
00028 
00029 #include <boost/shared_ptr.hpp>
00030 #include <boost/thread/mutex.hpp>
00031 #include <boost/thread/recursive_mutex.hpp>
00032 #include <boost/thread/condition.hpp>
00033 #include <boost/thread/thread_time.hpp>
00034 #include <boost/static_assert.hpp>
00035 #include <boost/bind.hpp>
00036 #include <boost/tuple/tuple.hpp>
00037 #include <boost/enable_shared_from_this.hpp> 
00038 #include <boost/format.hpp>
00039 
00040 #include <ros/callback_queue.h>
00041 #include <actionlib/client/action_client.h>
00042 #include <actionlib/client/simple_goal_state.h>
00043 #include <actionlib/client/simple_client_goal_state.h>
00044 #include <actionlib/client/terminal_state.h>
00045 
00046 #include <pr2_controllers_msgs/JointTrajectoryAction.h>
00047 #include <pr2_controllers_msgs/JointTrajectoryControllerState.h>
00048 #include <sensor_msgs/JointState.h>
00049 
00050 #define FOREACH(it, v) for(typeof((v).begin()) it = (v).begin(); it != (v).end(); (it)++)
00051 #define FOREACHC FOREACH
00052 
00053 using namespace OpenRAVE;
00054 using namespace std;
00055 
00056 namespace actionlib {
00057 template <class ActionSpec>
00058 class MyActionClient
00059 {
00060 private:
00061   ACTION_DEFINITION(ActionSpec);
00062   typedef ClientGoalHandle<ActionSpec> GoalHandleT;
00063   typedef MyActionClient<ActionSpec> MyActionClientT;
00064 
00065 public:
00066   typedef boost::function<void (const SimpleClientGoalState& state,  const ResultConstPtr& result) > SimpleDoneCallback;
00067   typedef boost::function<void () > SimpleActiveCallback;
00068   typedef boost::function<void (const FeedbackConstPtr& feedback) > SimpleFeedbackCallback;
00069 
00078   MyActionClient(const std::string& name, bool spin_thread = true) : cur_simple_state_(SimpleGoalState::PENDING)
00079   {
00080     initSimpleClient(nh_, name, spin_thread);
00081   }
00082 
00093   MyActionClient(ros::NodeHandle& n, const std::string& name, bool spin_thread = false) : cur_simple_state_(SimpleGoalState::PENDING)
00094   {
00095     initSimpleClient(n, name, spin_thread);
00096 
00097   }
00098 
00099   ~MyActionClient();
00100 
00110   bool waitForServer(const ros::Duration& timeout = ros::Duration(0,0) ) { return ac_->waitForActionServerToStart(timeout); }
00111 
00121   void sendGoal(const Goal& goal,
00122                 SimpleDoneCallback     done_cb     = SimpleDoneCallback(),
00123                 SimpleActiveCallback   active_cb   = SimpleActiveCallback(),
00124                 SimpleFeedbackCallback feedback_cb = SimpleFeedbackCallback());
00125 
00137   SimpleClientGoalState sendGoalAndWait(const Goal& goal,
00138                                         const ros::Duration& execute_timeout = ros::Duration(0,0),
00139                                         const ros::Duration& preempt_timeout = ros::Duration(0,0));
00140 
00146   bool waitForResult(const ros::Duration& timeout = ros::Duration(0,0) );
00147 
00152   ResultConstPtr getResult();
00153 
00160   SimpleClientGoalState getState();
00161 
00168   void cancelAllGoals();
00169 
00174   void cancelGoalsAtAndBeforeTime(const ros::Time& time);
00175 
00179   void cancelGoal();
00180 
00187   void stopTrackingGoal();
00188 
00189   bool isGoalExpired() { return gh_.isExpired(); }
00190 private:
00191   typedef ActionClient<ActionSpec> ActionClientT;
00192   ros::NodeHandle nh_;
00193   GoalHandleT gh_;
00194 
00195   SimpleGoalState cur_simple_state_;
00196 
00197   // Signalling Stuff
00198   boost::condition done_condition_;
00199   boost::mutex done_mutex_;
00200 
00201   // User Callbacks
00202   SimpleDoneCallback done_cb_;
00203   SimpleActiveCallback active_cb_;
00204   SimpleFeedbackCallback feedback_cb_;
00205 
00206   // Spin Thread Stuff
00207   boost::mutex terminate_mutex_;
00208   bool need_to_terminate_;
00209   boost::thread* spin_thread_;
00210   ros::CallbackQueue callback_queue;
00211 
00212   boost::scoped_ptr<ActionClientT> ac_;  // Action client depends on callback_queue, so it must be destroyed before callback_queue
00213 
00214   // ***** Private Funcs *****
00215   void initSimpleClient(ros::NodeHandle& n, const std::string& name, bool spin_thread);
00216   void handleTransition(GoalHandleT gh);
00217   void handleFeedback(GoalHandleT gh, const FeedbackConstPtr& feedback);
00218   void setSimpleState(const SimpleGoalState::StateEnum& next_state);
00219   void setSimpleState(const SimpleGoalState& next_state);
00220   void spinThread();
00221 };
00222 
00223 
00224 
00225 template<class ActionSpec>
00226 void MyActionClient<ActionSpec>::initSimpleClient(ros::NodeHandle& n, const std::string& name, bool spin_thread)
00227 {
00228   if (spin_thread)
00229   {
00230     ROS_DEBUG("Spinning up a thread for the MyActionClient");
00231     need_to_terminate_ = false;
00232     spin_thread_ = new boost::thread(boost::bind(&MyActionClient<ActionSpec>::spinThread, this));
00233     ac_.reset(new ActionClientT(n, name, &callback_queue));
00234   }
00235   else
00236   {
00237     spin_thread_ = NULL;
00238     ac_.reset(new ActionClientT(n, name));
00239   }
00240 }
00241 
00242 template<class ActionSpec>
00243 MyActionClient<ActionSpec>::~MyActionClient()
00244 {
00245   if (spin_thread_)
00246   {
00247     {
00248       boost::mutex::scoped_lock terminate_lock(terminate_mutex_);
00249       need_to_terminate_ = true;
00250     }
00251     spin_thread_->join();
00252     delete spin_thread_;
00253   }
00254   gh_.reset();
00255   ac_.reset();
00256 }
00257 
00258 template<class ActionSpec>
00259 void MyActionClient<ActionSpec>::spinThread()
00260 {
00261   while (nh_.ok())
00262   {
00263     {
00264       boost::mutex::scoped_lock terminate_lock(terminate_mutex_);
00265       if (need_to_terminate_)
00266         break;
00267     }
00268     callback_queue.callAvailable(ros::WallDuration(0.1f));
00269   }
00270 }
00271 
00272 template<class ActionSpec>
00273 void MyActionClient<ActionSpec>::setSimpleState(const SimpleGoalState::StateEnum& next_state)
00274 {
00275   setSimpleState( SimpleGoalState(next_state) );
00276 }
00277 
00278 template<class ActionSpec>
00279 void MyActionClient<ActionSpec>::setSimpleState(const SimpleGoalState& next_state)
00280 {
00281   ROS_DEBUG("Transitioning SimpleState from [%s] to [%s]",
00282             cur_simple_state_.toString().c_str(),
00283             next_state.toString().c_str());
00284   cur_simple_state_ = next_state;
00285 }
00286 
00287 template<class ActionSpec>
00288 void MyActionClient<ActionSpec>::sendGoal(const Goal& goal,
00289                                               SimpleDoneCallback     done_cb,
00290                                               SimpleActiveCallback   active_cb,
00291                                               SimpleFeedbackCallback feedback_cb)
00292 {
00293   // Reset the old GoalHandle, so that our callbacks won't get called anymore
00294   gh_.reset();
00295 
00296   // Store all the callbacks
00297   done_cb_     = done_cb;
00298   active_cb_   = active_cb;
00299   feedback_cb_ = feedback_cb;
00300 
00301   cur_simple_state_ = SimpleGoalState::PENDING;
00302 
00303   // Send the goal to the ActionServer
00304   gh_ = ac_->sendGoal(goal, boost::bind(&MyActionClientT::handleTransition, this, _1),
00305                             boost::bind(&MyActionClientT::handleFeedback, this, _1, _2));
00306 }
00307 
00308 template<class ActionSpec>
00309 SimpleClientGoalState MyActionClient<ActionSpec>::getState()
00310 {
00311   if (gh_.isExpired())
00312   {
00313     ROS_ERROR("Trying to getState() when no goal is running. You are incorrectly using MyActionClient");
00314     return SimpleClientGoalState(SimpleClientGoalState::LOST);
00315   }
00316 
00317   CommState comm_state_ = gh_.getCommState();
00318 
00319   switch( comm_state_.state_)
00320   {
00321     case CommState::WAITING_FOR_GOAL_ACK:
00322     case CommState::PENDING:
00323     case CommState::RECALLING:
00324       return SimpleClientGoalState(SimpleClientGoalState::PENDING);
00325     case CommState::ACTIVE:
00326     case CommState::PREEMPTING:
00327       return SimpleClientGoalState(SimpleClientGoalState::ACTIVE);
00328     case CommState::DONE:
00329     {
00330       switch(gh_.getTerminalState().state_)
00331       {
00332         case TerminalState::RECALLED:
00333           return SimpleClientGoalState(SimpleClientGoalState::RECALLED, gh_.getTerminalState().text_);
00334         case TerminalState::REJECTED:
00335           return SimpleClientGoalState(SimpleClientGoalState::REJECTED, gh_.getTerminalState().text_);
00336         case TerminalState::PREEMPTED:
00337           return SimpleClientGoalState(SimpleClientGoalState::PREEMPTED, gh_.getTerminalState().text_);
00338         case TerminalState::ABORTED:
00339           return SimpleClientGoalState(SimpleClientGoalState::ABORTED, gh_.getTerminalState().text_);
00340         case TerminalState::SUCCEEDED:
00341           return SimpleClientGoalState(SimpleClientGoalState::SUCCEEDED, gh_.getTerminalState().text_);
00342         case TerminalState::LOST:
00343           return SimpleClientGoalState(SimpleClientGoalState::LOST, gh_.getTerminalState().text_);
00344         default:
00345           ROS_ERROR("Unknown terminal state [%u]. This is a bug in MyActionClient", gh_.getTerminalState().state_);
00346           return SimpleClientGoalState(SimpleClientGoalState::LOST, gh_.getTerminalState().text_);
00347       }
00348     }
00349     case CommState::WAITING_FOR_RESULT:
00350     case CommState::WAITING_FOR_CANCEL_ACK:
00351     {
00352       switch (cur_simple_state_.state_)
00353       {
00354         case SimpleGoalState::PENDING:
00355           return SimpleClientGoalState(SimpleClientGoalState::PENDING);
00356         case SimpleGoalState::ACTIVE:
00357           return SimpleClientGoalState(SimpleClientGoalState::ACTIVE);
00358         case SimpleGoalState::DONE:
00359           ROS_ERROR("In WAITING_FOR_RESULT or WAITING_FOR_CANCEL_ACK, yet we are in SimpleGoalState DONE. This is a bug in MyActionClient");
00360           return SimpleClientGoalState(SimpleClientGoalState::LOST);
00361         default:
00362           ROS_ERROR("Got a SimpleGoalState of [%u]. This is a bug in MyActionClient", cur_simple_state_.state_);
00363       }
00364     }
00365     default:
00366       break;
00367   }
00368   ROS_ERROR("Error trying to interpret CommState - %u", comm_state_.state_);
00369   return SimpleClientGoalState(SimpleClientGoalState::LOST);
00370 }
00371 
00372 template<class ActionSpec>
00373 typename MyActionClient<ActionSpec>::ResultConstPtr MyActionClient<ActionSpec>::getResult()
00374 {
00375   if (gh_.isExpired())
00376     ROS_ERROR("Trying to getResult() when no goal is running. You are incorrectly using MyActionClient");
00377 
00378   if (gh_.getResult())
00379     return gh_.getResult();
00380 
00381   return ResultConstPtr(new Result);
00382 }
00383 
00384 
00385 template<class ActionSpec>
00386 void MyActionClient<ActionSpec>::cancelAllGoals()
00387 {
00388   ac_->cancelAllGoals();
00389 }
00390 
00391 template<class ActionSpec>
00392 void MyActionClient<ActionSpec>::cancelGoalsAtAndBeforeTime(const ros::Time& time)
00393 {
00394   ac_->cancelAllGoalsBeforeTime(time);
00395 }
00396 
00397 template<class ActionSpec>
00398 void MyActionClient<ActionSpec>::cancelGoal()
00399 {
00400   if (gh_.isExpired())
00401     ROS_ERROR("Trying to cancelGoal() when no goal is running. You are incorrectly using MyActionClient");
00402 
00403   gh_.cancel();
00404 }
00405 
00406 template<class ActionSpec>
00407 void MyActionClient<ActionSpec>::stopTrackingGoal()
00408 {
00409   if (gh_.isExpired())
00410     ROS_ERROR("Trying to stopTrackingGoal() when no goal is running. You are incorrectly using MyActionClient");
00411   gh_.reset();
00412 }
00413 
00414 template<class ActionSpec>
00415 void MyActionClient<ActionSpec>::handleFeedback(GoalHandleT gh, const FeedbackConstPtr& feedback)
00416 {
00417   if (gh_ != gh)
00418     ROS_ERROR("Got a callback on a goalHandle that we're not tracking.  \
00419                This is an internal MyActionClient/ActionClient bug.  \
00420                This could also be a GoalID collision");
00421   if (feedback_cb_)
00422     feedback_cb_(feedback);
00423 }
00424 
00425 template<class ActionSpec>
00426 void MyActionClient<ActionSpec>::handleTransition(GoalHandleT gh)
00427 {
00428   CommState comm_state_ = gh.getCommState();
00429   switch (comm_state_.state_)
00430   {
00431     case CommState::WAITING_FOR_GOAL_ACK:
00432       ROS_ERROR("BUG: Shouldn't ever get a transition callback for WAITING_FOR_GOAL_ACK");
00433       break;
00434     case CommState::PENDING:
00435       ROS_ERROR_COND( cur_simple_state_ != SimpleGoalState::PENDING,
00436                       "BUG: Got a transition to CommState [%s] when our in SimpleGoalState [%s]",
00437                       comm_state_.toString().c_str(), cur_simple_state_.toString().c_str());
00438       break;
00439     case CommState::ACTIVE:
00440       switch (cur_simple_state_.state_)
00441       {
00442         case SimpleGoalState::PENDING:
00443           setSimpleState(SimpleGoalState::ACTIVE);
00444           if (active_cb_)
00445             active_cb_();
00446           break;
00447         case SimpleGoalState::ACTIVE:
00448           break;
00449         case SimpleGoalState::DONE:
00450           ROS_ERROR("BUG: Got a transition to CommState [%s] when in SimpleGoalState [%s]",
00451                     comm_state_.toString().c_str(), cur_simple_state_.toString().c_str());
00452           break;
00453         default:
00454           ROS_FATAL("Unknown SimpleGoalState %u", cur_simple_state_.state_);
00455           break;
00456       }
00457       break;
00458     case CommState::WAITING_FOR_RESULT:
00459       break;
00460     case CommState::WAITING_FOR_CANCEL_ACK:
00461       break;
00462     case CommState::RECALLING:
00463       ROS_ERROR_COND( cur_simple_state_ != SimpleGoalState::PENDING,
00464                       "BUG: Got a transition to CommState [%s] when our in SimpleGoalState [%s]",
00465                       comm_state_.toString().c_str(), cur_simple_state_.toString().c_str());
00466       break;
00467     case CommState::PREEMPTING:
00468       switch (cur_simple_state_.state_)
00469       {
00470         case SimpleGoalState::PENDING:
00471           setSimpleState(SimpleGoalState::ACTIVE);
00472           if (active_cb_)
00473             active_cb_();
00474           break;
00475         case SimpleGoalState::ACTIVE:
00476           break;
00477         case SimpleGoalState::DONE:
00478           ROS_ERROR("BUG: Got a transition to CommState [%s] when in SimpleGoalState [%s]",
00479                      comm_state_.toString().c_str(), cur_simple_state_.toString().c_str());
00480           break;
00481         default:
00482           ROS_FATAL("Unknown SimpleGoalState %u", cur_simple_state_.state_);
00483           break;
00484       }
00485       break;
00486     case CommState::DONE:
00487       switch (cur_simple_state_.state_)
00488       {
00489         case SimpleGoalState::PENDING:
00490         case SimpleGoalState::ACTIVE:
00491           done_mutex_.lock();
00492           setSimpleState(SimpleGoalState::DONE);
00493           done_mutex_.unlock();
00494 
00495           if (done_cb_)
00496             done_cb_(getState(), gh.getResult());
00497 
00498           done_condition_.notify_all();
00499           break;
00500         case SimpleGoalState::DONE:
00501           ROS_ERROR("BUG: Got a second transition to DONE");
00502           break;
00503         default:
00504           ROS_FATAL("Unknown SimpleGoalState %u", cur_simple_state_.state_);
00505           break;
00506       }
00507       break;
00508     default:
00509       ROS_ERROR("Unknown CommState received [%u]", comm_state_.state_);
00510       break;
00511   }
00512 }
00513 
00514 template<class ActionSpec>
00515 bool MyActionClient<ActionSpec>::waitForResult(const ros::Duration& timeout )
00516 {
00517   if (gh_.isExpired())
00518   {
00519     ROS_ERROR("Trying to waitForGoalToFinish() when no goal is running. You are incorrectly using MyActionClient");
00520     return false;
00521   }
00522 
00523   if (timeout < ros::Duration(0,0))
00524     ROS_WARN("Timeouts can't be negative. Timeout is [%.2fs]", timeout.toSec());
00525 
00526   ros::Time timeout_time = ros::Time::now() + timeout;
00527 
00528   boost::mutex::scoped_lock lock(done_mutex_);
00529 
00530   // Hardcode how often we check for node.ok()
00531   ros::Duration loop_period = ros::Duration().fromSec(.1);
00532 
00533   while (nh_.ok())
00534   {
00535     // Determine how long we should wait
00536     ros::Duration time_left = timeout_time - ros::Time::now();
00537 
00538     // Check if we're past the timeout time
00539     if (timeout > ros::Duration(0,0) && time_left <= ros::Duration(0,0) )
00540       break;
00541 
00542     if (cur_simple_state_ == SimpleGoalState::DONE)
00543       break;
00544 
00545     // Truncate the time left
00546     if (time_left > loop_period || timeout == ros::Duration())
00547       time_left = loop_period;
00548 
00549     done_condition_.timed_wait(lock, boost::posix_time::milliseconds(time_left.toSec() * 1000.0f));
00550   }
00551 
00552   return (cur_simple_state_ == SimpleGoalState::DONE);
00553 }
00554 
00555 template<class ActionSpec>
00556 SimpleClientGoalState MyActionClient<ActionSpec>::sendGoalAndWait(const Goal& goal,
00557                                                                       const ros::Duration& execute_timeout,
00558                                                                       const ros::Duration& preempt_timeout)
00559 {
00560   sendGoal(goal);
00561 
00562   // See if the goal finishes in time
00563   if (waitForResult(execute_timeout))
00564   {
00565     ROS_DEBUG("Goal finished within specified execute_timeout [%.2f]", execute_timeout.toSec());
00566     return getState();
00567   }
00568 
00569   ROS_DEBUG("Goal finished within specified execute_timeout [%.2f]", execute_timeout.toSec());
00570 
00571   // It didn't finish in time, so we need to preempt it
00572   cancelGoal();
00573 
00574   // Now wait again and see if it finishes
00575   if (waitForResult(preempt_timeout))
00576     ROS_DEBUG("Preempt finished within specified preempt_timeout [%.2f]", preempt_timeout.toSec());
00577   else
00578     ROS_DEBUG("Preempt didn't finish specified preempt_timeout [%.2f]", preempt_timeout.toSec());
00579   return getState();
00580 }
00581 
00582 }
00583 
00584 class ROSActionLibController : public ControllerBase
00585 {
00586 public:
00587  ROSActionLibController(EnvironmentBasePtr penv, std::istream& ss) : ControllerBase(penv) {
00588         __description = ":Interface Author: Rosen Diankov\n\nAllows OpenRAVE to control a robot through the ROS actionlib interface.";
00589         _bDestroyThread = true;
00590         _nControlTransformation = 0;
00591         _jointstatetopic="/joint_states";
00592         string cmd;
00593         while(!ss.eof()) {
00594             ss >> cmd;
00595             if( !ss ) {
00596                 break;
00597             }
00598 
00599             if( cmd == "jointstate") 
00600                 ss >> _jointstatetopic;
00601             else if( cmd == "state")
00602                 ss >> _controllerstatetopic;
00603             else if( cmd == "action" )
00604                 ss >> _actiontopic;
00605             else
00606                 break;
00607         }
00608     }
00609     virtual ~ROSActionLibController() {
00610         _Destroy();
00611     }
00612     
00613     virtual bool Init(RobotBasePtr robot, const std::vector<int>& dofindices, int nControlTransformation)
00614     {
00615         _Destroy();
00616         _probot = robot;
00617         _dofindices = dofindices;
00618         _nControlTransformation = nControlTransformation;
00619 
00620         int argc=0;
00621         ros::init(argc,NULL,"openrave", ros::init_options::NoSigintHandler|ros::init_options::AnonymousName);
00622         if( !ros::master::check() ) {
00623             return false;
00624         }
00625         
00626         _node.reset(new ros::NodeHandle());
00627         _bDestroyThread = false;
00628         _threadros = boost::thread(boost::bind(&ROSActionLibController::_threadrosfn, this));
00629 
00630         _subjointstate = _node->subscribe(_jointstatetopic, 10, &ROSActionLibController::_jointstatecb, this);
00631         if( _controllerstatetopic.size() > 0 )
00632             _subcontrollerstate = _node->subscribe(_controllerstatetopic,1,&ROSActionLibController::_controllerstatecb, this);
00633         else {
00634             RAVELOG_WARN("no controller state topic, filling map joints with default\n");
00635             FOREACHC(itjoint,_probot->GetJoints()) {
00636                 _vjointnames.push_back(make_pair((*itjoint)->GetName(), (*itjoint)->GetJointIndex()));
00637             }
00638         }
00639 
00640         _probot->GetDOFValues(_vlastjointvalues);
00641         _vlastjointvel.resize(0);
00642         _vlastjointvel.resize(_vlastjointvalues.size(),0.0f);
00643         _vlastjointtorque = _vlastjointvel;
00644 
00645         return true;
00646     }
00647 
00648     virtual const std::vector<int>& GetControlDOFIndices() const { return _dofindices; }
00649     virtual int IsControlTransformation() const { return _nControlTransformation; }
00650 
00651     virtual void Reset(int options)
00652     {
00653         if( !!_ac ) {
00654             _ac->cancelAllGoals();
00655             _bHasGoal = false;
00656         }
00657     }
00658 
00659     virtual bool SetDesired(const std::vector<dReal>& values, TransformConstPtr trans)
00660     {
00661         TrajectoryBasePtr ptraj;
00662         {
00663             EnvironmentMutex::scoped_lock lockenv(GetEnv()->GetMutex());
00664             ptraj = RaveCreateTrajectory(GetEnv(),_probot->GetDOF());
00665             vector<dReal> vcurrentvalues;
00666             _probot->GetDOFValues(vcurrentvalues);
00667             ptraj->AddPoint(TrajectoryBase::TPOINT(vcurrentvalues,0));
00668             ptraj->AddPoint(TrajectoryBase::TPOINT(values,0));
00669             ptraj->CalcTrajTiming(_probot,TrajectoryBase::LINEAR,true,false);
00670         }
00671         
00672         return SetPath(ptraj);
00673     }
00674     
00675     virtual bool SetPath(TrajectoryBaseConstPtr ptraj)
00676     {
00677         if( ptraj->GetTotalDuration() <= 0 || ptraj->GetPoints().size() == 0 )
00678             return false;
00679         boost::mutex::scoped_lock lock(_mutex);
00680         if( _vjointnames.size() == 0 ) {
00681             RAVELOG_INFO("joint names not initialized\n");
00682             return false;
00683         }
00684         _checkaction();
00685         if( !_ac )
00686             return false;
00687         _ac->cancelAllGoals();
00688         pr2_controllers_msgs::JointTrajectoryGoal goal;
00689         goal.trajectory.header.stamp = ros::Time::now()+ros::Duration(0.2); // start in 100ms
00690         goal.trajectory.joint_names.reserve(_vjointnames.size());
00691         vector<int> vindices;
00692         FOREACH(itname,_vjointnames) {
00693             goal.trajectory.joint_names.push_back(itname->first);
00694             BOOST_ASSERT(itname->second<ptraj->GetDOF());
00695             vindices.push_back(itname->second);
00696         }
00697         FOREACHC(itpoint,ptraj->GetPoints()) {
00698             trajectory_msgs::JointTrajectoryPoint pt;
00699             pt.positions.reserve(vindices.size());
00700             pt.velocities.reserve(vindices.size());
00701             FOREACH(it,vindices) {
00702                 pt.positions.push_back(itpoint->q[*it]);
00703                 pt.velocities.push_back(itpoint->qdot[*it]);
00704             }
00705             pt.time_from_start.fromSec((double)itpoint->time);
00706             goal.trajectory.points.push_back(pt);
00707         }
00708 
00709         _ac->sendGoal(goal);
00710         _bHasGoal = true;
00711         return true;
00712     }
00713 
00714     virtual void SimulationStep(dReal fTimeElapsed)
00715     {
00716     }
00717 
00718     virtual bool IsDone()
00719     {
00720         if( !_bHasGoal || !_ac )
00721             return true;
00722         if( _ac->isGoalExpired() )
00723             return true;
00724         if( !_ac->waitForResult(ros::Duration(0.0001)) )
00725             return false;
00726         return _ac->getState() == actionlib::SimpleClientGoalState::SUCCEEDED;
00727     }
00728 
00729     virtual dReal GetTime() const
00730     {
00731         return !_ac ? 0 : (ros::Time::now()-_actiontime).toSec();
00732     }
00733 
00734     virtual void GetVelocity(std::vector<dReal>& vel) const {
00735         boost::mutex::scoped_lock lock(_mutex);
00736         vel = _vlastjointvel;
00737     }
00738 
00739     virtual void GetTorque(std::vector<dReal>& torque) const {
00740         boost::mutex::scoped_lock lock(_mutex);
00741         torque = _vlastjointtorque;
00742     }
00743     
00744     virtual RobotBasePtr GetRobot() const { return _probot; }
00745 
00746 protected:
00747     virtual void _Destroy()
00748     {
00749         if( !!_ac ) {
00750             _ac->cancelAllGoals();
00751             _ac.reset();
00752             _bHasGoal = false;
00753         }
00754 
00755         _bDestroyThread = true;
00756         _node.reset();
00757         _subjointstate.shutdown();
00758         _subcontrollerstate.shutdown();
00759         _threadros.join(); // deadlock condition with environment
00760         _probot.reset();
00761         _vjointnames.clear();
00762     }
00763     
00764     virtual void _jointstatecb(const sensor_msgs::JointStateConstPtr& jstate)
00765     {
00766         boost::mutex::scoped_lock lock(_mutex);
00767         if( _bDestroyThread )
00768             return;
00769         EnvironmentMutex::scoped_lock lockenv(GetEnv()->GetMutex());
00770         _probot->GetDOFValues(_vlastjointvalues);
00771         //resize the vel and torque vectors if necessary:
00772         _vlastjointvel.resize(_vlastjointvalues.size(),0.0f);
00773         _vlastjointtorque.resize(_vlastjointvalues.size(),0.0f);
00774         for(size_t i = 0; i < jstate->name.size(); ++i) {
00775             KinBody::JointPtr pjoint = _probot->GetJoint(jstate->name[i]);
00776             if( !pjoint ) {
00777                 RAVELOG_VERBOSE(str(boost::format("could not find joint %s\n")%jstate->name[i]));
00778                 continue;
00779             }
00780             else {
00781                 _vlastjointvalues.at(pjoint->GetJointIndex()) = jstate->position.at(i);
00782                 _vlastjointvel.at(pjoint->GetJointIndex()) = jstate->velocity.at(i);
00783                 _vlastjointtorque.at(pjoint->GetJointIndex()) = jstate->effort.at(i);
00784             }
00785         }
00786         _probot->SetJointValues(_vlastjointvalues);
00787     }
00788 
00789     virtual void _controllerstatecb(const pr2_controllers_msgs::JointTrajectoryControllerStateConstPtr& cstate)
00790     {
00791         boost::mutex::scoped_lock lock(_mutex);
00792         if( _bDestroyThread )
00793             return;
00794         _vjointnames.clear();
00795         FOREACH(itname,cstate->joint_names) {
00796             KinBody::JointPtr pjoint = _probot->GetJoint(*itname);
00797             _vjointnames.push_back(make_pair(*itname, pjoint->GetJointIndex()));
00798         }
00799     }
00800     
00801     virtual void _threadrosfn()
00802     {
00803         while(!_bDestroyThread && ros::ok()) {
00804             ros::spinOnce();
00805             usleep(1000); // query every 1ms?
00806         }
00807     }
00808 
00809     virtual void _checkaction()
00810     {
00811         if( _actiontopic.size() == 0 )
00812             return;
00813         
00814         if( !!_ac ) {
00815             // check if still valid
00816             return;
00817         }
00818         
00819         _ac.reset(new actionlib::MyActionClient<pr2_controllers_msgs::JointTrajectoryAction>(_actiontopic,true));
00820         ros::Time start = ros::Time::now();
00821         if( !_ac->waitForServer(ros::Duration(10.0)) ) {
00822             _ac.reset();
00823             RAVELOG_WARN(str(boost::format("failed to connect to action %s\n")%_actiontopic));
00824         }
00825     }
00826 
00827     bool _bDestroyThread;
00828     RobotBasePtr _probot;           
00829     boost::shared_ptr<actionlib::MyActionClient<pr2_controllers_msgs::JointTrajectoryAction> > _ac;
00830     boost::shared_ptr<ros::NodeHandle> _node;
00831     boost::thread _threadros;
00832     string _actiontopic;
00833     pr2_controllers_msgs::JointTrajectoryControllerState _cstate;
00834     ros::Subscriber _subjointstate, _subcontrollerstate;
00835     ros::Time _actiontime;
00836     vector<dReal> _vlastjointvalues, _vlastjointvel, _vlastjointtorque;
00837     vector< pair<string,int> > _vjointnames;
00838     mutable boost::mutex _mutex;
00839     bool _bHasGoal;
00840     std::vector<int> _dofindices;
00841     int _nControlTransformation;
00842     string _jointstatetopic, _controllerstatetopic;
00843 };
00844 
00845 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends Defines


openrave_actionlib
Author(s): rdiankov
autogenerated on Sun Mar 24 2013 05:08:46