00001 #include <moveit_controller_multidof/RobotTrajectoryExecutor.h>
00002 #include <moveit_controller_multidof/PathConverter.h>
00003
00004
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
00028
00029
00030
00031
00032
00033
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
00053
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
00080
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
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
00143
00144
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
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
00163
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
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
00228 if (active_request) {
00229
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
00254
00255 setLastStateFrom(state);
00256
00257 if (state!=actionlib::SimpleClientGoalState::SUCCEEDED) {
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
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
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
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
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();
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
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
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