00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #ifndef OPENRAVE_ACTIONLIB_H
00017 #define OPENRAVE_ACTIONLIB_H
00018
00019 #include <rave/rave.h>
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
00198 boost::condition done_condition_;
00199 boost::mutex done_mutex_;
00200
00201
00202 SimpleDoneCallback done_cb_;
00203 SimpleActiveCallback active_cb_;
00204 SimpleFeedbackCallback feedback_cb_;
00205
00206
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_;
00213
00214
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
00294 gh_.reset();
00295
00296
00297 done_cb_ = done_cb;
00298 active_cb_ = active_cb;
00299 feedback_cb_ = feedback_cb;
00300
00301 cur_simple_state_ = SimpleGoalState::PENDING;
00302
00303
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
00531 ros::Duration loop_period = ros::Duration().fromSec(.1);
00532
00533 while (nh_.ok())
00534 {
00535
00536 ros::Duration time_left = timeout_time - ros::Time::now();
00537
00538
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
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
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
00572 cancelGoal();
00573
00574
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);
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();
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
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);
00806 }
00807 }
00808
00809 virtual void _checkaction()
00810 {
00811 if( _actiontopic.size() == 0 )
00812 return;
00813
00814 if( !!_ac ) {
00815
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