joint_trajectory_action.cpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2014, Fraunhofer IPA
5  * Author: Thiago de Freitas
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  * * Neither the name of the Fraunhofer IPA, nor the names
18  * of its contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
38 #include <industrial_utils/utils.h>
39 #include <map>
40 #include <string>
41 #include <vector>
42 
44 
46 {
47 namespace joint_trajectory_action
48 {
49 
50 const double JointTrajectoryAction::WATCHD0G_PERIOD_ = 1.0;
52 
54  action_server_(node_, "joint_trajectory_action",
55  boost::bind(&JointTrajectoryAction::goalCB, this, _1),
56  boost::bind(&JointTrajectoryAction::cancelCB, this, _1), false)
57 {
58  ros::NodeHandle pn("~");
59 
60  pn.param("constraints/goal_threshold", goal_threshold_, DEFAULT_GOAL_THRESHOLD_);
61 
62  std::map<int, RobotGroup> robot_groups;
63  getJointGroups("topic_list", robot_groups);
64 
65  for (size_t i = 0; i < robot_groups.size(); i++)
66  {
67  std::string joint_path_action_name = robot_groups[i].get_ns() + "/" + robot_groups[i].get_name();
68  std::vector<std::string> rg_joint_names = robot_groups[i].get_joint_names();
69  int group_number_int = robot_groups[i].get_group_id();
70 
71  all_joint_names_.insert(all_joint_names_.end(), rg_joint_names.begin(), rg_joint_names.end());
72 
74  node_, joint_path_action_name + "/joint_trajectory_action" , false);
75  actionServer_->registerGoalCallback(
76  boost::bind(&JointTrajectoryAction::goalCB,
77  this, _1, group_number_int));
78  actionServer_->registerCancelCallback(
79  boost::bind(&JointTrajectoryAction::cancelCB,
80  this, _1, group_number_int));
81 
82  pub_trajectory_command_ = node_.advertise<motoman_msgs::DynamicJointTrajectory>(
83  joint_path_action_name + "/joint_path_command", 1);
84  sub_trajectory_state_ = this->node_.subscribe<control_msgs::FollowJointTrajectoryFeedback>(
85  joint_path_action_name + "/feedback_states", 1,
86  boost::bind(&JointTrajectoryAction::controllerStateCB,
87  this, _1, group_number_int));
88  sub_robot_status_ = node_.subscribe(
89  "robot_status", 1, &JointTrajectoryAction::robotStatusCB, this);
90 
91  pub_trajectories_[group_number_int] = pub_trajectory_command_;
92  sub_trajectories_[group_number_int] = (sub_trajectory_state_);
93  sub_status_[group_number_int] = (sub_robot_status_);
94 
95  this->act_servers_[group_number_int] = actionServer_;
96 
97  this->act_servers_[group_number_int]->start();
98 
99  this->watchdog_timer_map_[group_number_int] = node_.createTimer(
100  ros::Duration(WATCHD0G_PERIOD_), boost::bind(
101  &JointTrajectoryAction::watchdog, this, _1, group_number_int));
102  }
103 
104  pub_trajectory_command_ = node_.advertise<motoman_msgs::DynamicJointTrajectory>(
105  "joint_path_command", 1);
106 
107  this->robot_groups_ = robot_groups;
108 
109  action_server_.start();
110 }
111 
112 JointTrajectoryAction::~JointTrajectoryAction()
113 {
114 }
115 
116 void JointTrajectoryAction::robotStatusCB(
117  const industrial_msgs::RobotStatusConstPtr &msg)
118 {
119  last_robot_status_ = msg; // caching robot status for later use.
120 }
121 
122 void JointTrajectoryAction::watchdog(const ros::TimerEvent &e)
123 {
124  // Some debug logging
125  if (!last_trajectory_state_)
126  {
127  ROS_DEBUG("Waiting for subscription to joint trajectory state");
128  }
129  if (!trajectory_state_recvd_)
130  {
131  ROS_DEBUG("Trajectory state not received since last watchdog");
132  }
133 
134  // Aborts the active goal if the controller does not appear to be active.
135  if (has_active_goal_)
136  {
137  if (!trajectory_state_recvd_)
138  {
139  // last_trajectory_state_ is null if the subscriber never makes a connection
140  if (!last_trajectory_state_)
141  {
142  ROS_WARN("Aborting goal because we have never heard a controller state message.");
143  }
144  else
145  {
147  "Aborting goal because we haven't heard from the controller in " << WATCHD0G_PERIOD_ << " seconds");
148  }
149  abortGoal();
150  }
151  }
152 
153  // Reset the trajectory state received flag
154  trajectory_state_recvd_ = false;
155 }
156 
157 void JointTrajectoryAction::watchdog(const ros::TimerEvent &e, int group_number)
158 {
159  // Some debug logging
160  if (!last_trajectory_state_map_[group_number])
161  {
162  ROS_DEBUG("Waiting for subscription to joint trajectory state");
163  }
164  if (!trajectory_state_recvd_map_[group_number])
165  {
166  ROS_DEBUG("Trajectory state not received since last watchdog");
167  }
168 
169  // Aborts the active goal if the controller does not appear to be active.
170  if (has_active_goal_map_[group_number])
171  {
172  if (!trajectory_state_recvd_map_[group_number])
173  {
174  // last_trajectory_state_ is null if the subscriber never makes a connection
175  if (!last_trajectory_state_map_[group_number])
176  {
177  ROS_WARN("Aborting goal because we have never heard a controller state message.");
178  }
179  else
180  {
182  "Aborting goal because we haven't heard from the controller in " << WATCHD0G_PERIOD_ << " seconds");
183  }
184  abortGoal(group_number);
185  }
186  }
187  // Reset the trajectory state received flag
188  trajectory_state_recvd_ = false;
189 }
190 
191 void JointTrajectoryAction::goalCB(JointTractoryActionServer::GoalHandle gh)
192 {
193  gh.setAccepted();
194 
195  int group_number;
196 
197 // TODO(thiagodefreitas): change for getting the id from the group instead of a sequential checking on the map
198 
199  ros::Duration last_time_from_start(0.0);
200 
201  motoman_msgs::DynamicJointTrajectory dyn_traj;
202 
203  for (size_t i = 0; i < gh.getGoal()->trajectory.points.size(); i++)
204  {
205  motoman_msgs::DynamicJointPoint dpoint;
206 
207  for (size_t rbt_idx = 0; rbt_idx < robot_groups_.size(); rbt_idx++)
208  {
209  size_t ros_idx = std::find(
210  gh.getGoal()->trajectory.joint_names.begin(),
211  gh.getGoal()->trajectory.joint_names.end(),
212  robot_groups_[rbt_idx].get_joint_names()[0])
213  - gh.getGoal()->trajectory.joint_names.begin();
214 
215  bool is_found = ros_idx < gh.getGoal()->trajectory.joint_names.size();
216 
217  group_number = rbt_idx;
218  motoman_msgs::DynamicJointsGroup dyn_group;
219 
220  int num_joints = robot_groups_[group_number].get_joint_names().size();
221 
222  if (is_found)
223  {
224  if (gh.getGoal()->trajectory.points[i].positions.empty())
225  {
226  std::vector<double> positions(num_joints, 0.0);
227  dyn_group.positions = positions;
228  }
229  else
230  dyn_group.positions.insert(
231  dyn_group.positions.begin(),
232  gh.getGoal()->trajectory.points[i].positions.begin() + ros_idx,
233  gh.getGoal()->trajectory.points[i].positions.begin() + ros_idx
234  + robot_groups_[rbt_idx].get_joint_names().size());
235 
236  if (gh.getGoal()->trajectory.points[i].velocities.empty())
237  {
238  std::vector<double> velocities(num_joints, 0.0);
239  dyn_group.velocities = velocities;
240  }
241  else
242  dyn_group.velocities.insert(
243  dyn_group.velocities.begin(),
244  gh.getGoal()->trajectory.points[i].velocities.begin()
245  + ros_idx, gh.getGoal()->trajectory.points[i].velocities.begin()
246  + ros_idx + robot_groups_[rbt_idx].get_joint_names().size());
247 
248  if (gh.getGoal()->trajectory.points[i].accelerations.empty())
249  {
250  std::vector<double> accelerations(num_joints, 0.0);
251  dyn_group.accelerations = accelerations;
252  }
253  else
254  dyn_group.accelerations.insert(
255  dyn_group.accelerations.begin(),
256  gh.getGoal()->trajectory.points[i].accelerations.begin()
257  + ros_idx, gh.getGoal()->trajectory.points[i].accelerations.begin()
258  + ros_idx + robot_groups_[rbt_idx].get_joint_names().size());
259  if (gh.getGoal()->trajectory.points[i].effort.empty())
260  {
261  std::vector<double> effort(num_joints, 0.0);
262  dyn_group.effort = effort;
263  }
264  else
265  dyn_group.effort.insert(
266  dyn_group.effort.begin(),
267  gh.getGoal()->trajectory.points[i].effort.begin()
268  + ros_idx, gh.getGoal()->trajectory.points[i].effort.begin()
269  + ros_idx + robot_groups_[rbt_idx].get_joint_names().size());
270  dyn_group.time_from_start = gh.getGoal()->trajectory.points[i].time_from_start;
271  dyn_group.group_number = group_number;
272  dyn_group.num_joints = dyn_group.positions.size();
273  }
274 
275  // Generating message for groups that were not present in the trajectory message
276  else
277  {
278  std::vector<double> positions(num_joints, 0.0);
279  std::vector<double> velocities(num_joints, 0.0);
280  std::vector<double> accelerations(num_joints, 0.0);
281  std::vector<double> effort(num_joints, 0.0);
282 
283  dyn_group.positions = positions;
284  dyn_group.velocities = velocities;
285  dyn_group.accelerations = accelerations;
286  dyn_group.effort = effort;
287 
288  dyn_group.time_from_start = gh.getGoal()->trajectory.points[i].time_from_start;
289  dyn_group.group_number = group_number;
290  dyn_group.num_joints = num_joints;
291  }
292 
293  dpoint.groups.push_back(dyn_group);
294  }
295  dpoint.num_groups = dpoint.groups.size();
296  dyn_traj.points.push_back(dpoint);
297  }
298  dyn_traj.header = gh.getGoal()->trajectory.header;
299  dyn_traj.header.stamp = ros::Time::now();
300  // Publishing the joint names for the 4 groups
301  dyn_traj.joint_names = all_joint_names_;
302 
303  this->pub_trajectory_command_.publish(dyn_traj);
304 }
305 
306 void JointTrajectoryAction::cancelCB(JointTractoryActionServer::GoalHandle gh)
307 {
308  // The interface is provided, but it is recommended to use
309  // void JointTrajectoryAction::cancelCB(JointTractoryActionServer::GoalHandle & gh, int group_number)
310 
311  ROS_DEBUG("Received action cancel request");
312 }
313 
314 void JointTrajectoryAction::goalCB(JointTractoryActionServer::GoalHandle gh, int group_number)
315 {
316  if (!gh.getGoal()->trajectory.points.empty())
317  {
319  this->robot_groups_[group_number].get_joint_names(),
320  gh.getGoal()->trajectory.joint_names))
321  {
322  // Cancels the currently active goal.
323  if (has_active_goal_map_[group_number])
324  {
325  ROS_WARN("Received new goal, canceling current goal");
326  abortGoal(group_number);
327  }
328  // Sends the trajectory along to the controller
329  if (withinGoalConstraints(last_trajectory_state_map_[group_number],
330  gh.getGoal()->trajectory, group_number))
331  {
332  ROS_INFO_STREAM("Already within goal constraints, setting goal succeeded");
333  gh.setAccepted();
334  gh.setSucceeded();
335  has_active_goal_map_[group_number] = false;
336  }
337  else
338  {
339  gh.setAccepted();
340  active_goal_map_[group_number] = gh;
341  has_active_goal_map_[group_number] = true;
342 
343  ROS_INFO("Publishing trajectory");
344 
345  current_traj_map_[group_number] = active_goal_map_[group_number].getGoal()->trajectory;
346 
347  int num_joints = robot_groups_[group_number].get_joint_names().size();
348 
349  motoman_msgs::DynamicJointTrajectory dyn_traj;
350 
351  for (size_t i = 0; i < current_traj_map_[group_number].points.size(); ++i)
352  {
353  motoman_msgs::DynamicJointsGroup dyn_group;
354  motoman_msgs::DynamicJointPoint dyn_point;
355 
356  if (gh.getGoal()->trajectory.points[i].positions.empty())
357  {
358  std::vector<double> positions(num_joints, 0.0);
359  dyn_group.positions = positions;
360  }
361  else
362  dyn_group.positions = gh.getGoal()->trajectory.points[i].positions;
363 
364  if (gh.getGoal()->trajectory.points[i].velocities.empty())
365  {
366  std::vector<double> velocities(num_joints, 0.0);
367  dyn_group.velocities = velocities;
368  }
369  else
370  dyn_group.velocities = gh.getGoal()->trajectory.points[i].velocities;
371  if (gh.getGoal()->trajectory.points[i].accelerations.empty())
372  {
373  std::vector<double> accelerations(num_joints, 0.0);
374  dyn_group.accelerations = accelerations;
375  }
376  else
377  dyn_group.accelerations = gh.getGoal()->trajectory.points[i].accelerations;
378  if (gh.getGoal()->trajectory.points[i].effort.empty())
379  {
380  std::vector<double> effort(num_joints, 0.0);
381  dyn_group.effort = effort;
382  }
383  else
384  dyn_group.effort = gh.getGoal()->trajectory.points[i].effort;
385  dyn_group.time_from_start = gh.getGoal()->trajectory.points[i].time_from_start;
386  dyn_group.group_number = group_number;
387  dyn_group.num_joints = robot_groups_[group_number].get_joint_names().size();
388  dyn_point.groups.push_back(dyn_group);
389 
390  dyn_point.num_groups = 1;
391  dyn_traj.points.push_back(dyn_point);
392  }
393  dyn_traj.header = gh.getGoal()->trajectory.header;
394  dyn_traj.joint_names = gh.getGoal()->trajectory.joint_names;
395  this->pub_trajectories_[group_number].publish(dyn_traj);
396  }
397  }
398  else
399  {
400  ROS_ERROR("Joint trajectory action failing on invalid joints");
401  control_msgs::FollowJointTrajectoryResult rslt;
402  rslt.error_code = control_msgs::FollowJointTrajectoryResult::INVALID_JOINTS;
403  gh.setRejected(rslt, "Joint names do not match");
404  }
405  }
406  else
407  {
408  ROS_ERROR("Joint trajectory action failed on empty trajectory");
409  control_msgs::FollowJointTrajectoryResult rslt;
410  rslt.error_code = control_msgs::FollowJointTrajectoryResult::INVALID_GOAL;
411  gh.setRejected(rslt, "Empty trajectory");
412  }
413 
414  // Adding some informational log messages to indicate unsupported goal constraints
415  if (gh.getGoal()->goal_time_tolerance.toSec() > 0.0)
416  {
417  ROS_WARN_STREAM("Ignoring goal time tolerance in action goal, may be supported in the future");
418  }
419  if (!gh.getGoal()->goal_tolerance.empty())
420  {
422  "Ignoring goal tolerance in action, using paramater tolerance of " << goal_threshold_ << " instead");
423  }
424  if (!gh.getGoal()->path_tolerance.empty())
425  {
426  ROS_WARN_STREAM("Ignoring goal path tolerance, option not supported by ROS-Industrial drivers");
427  }
428 }
429 
430 void JointTrajectoryAction::cancelCB(
431  JointTractoryActionServer::GoalHandle gh, int group_number)
432 {
433  ROS_DEBUG("Received action cancel request");
434  if (active_goal_map_[group_number] == gh)
435  {
436  // Stops the controller.
437  motoman_msgs::DynamicJointTrajectory empty;
438  empty.joint_names = robot_groups_[group_number].get_joint_names();
439  this->pub_trajectories_[group_number].publish(empty);
440 
441  // Marks the current goal as canceled.
442  active_goal_map_[group_number].setCanceled();
443  has_active_goal_map_[group_number] = false;
444  }
445  else
446  {
447  ROS_WARN("Active goal and goal cancel do not match, ignoring cancel request");
448  }
449 }
450 
451 void JointTrajectoryAction::controllerStateCB(
452  const control_msgs::FollowJointTrajectoryFeedbackConstPtr &msg, int robot_id)
453 {
454  ROS_DEBUG("Checking controller state feedback");
455  last_trajectory_state_map_[robot_id] = msg;
456  trajectory_state_recvd_map_[robot_id] = true;
457 
458  if (!has_active_goal_map_[robot_id])
459  {
460  ROS_DEBUG("No active goal, ignoring feedback");
461  return;
462  }
463 
464  if (current_traj_map_[robot_id].points.empty())
465  {
466  ROS_DEBUG("Current trajectory is empty, ignoring feedback");
467  return;
468  }
469 
470  if (!industrial_utils::isSimilar(robot_groups_[robot_id].get_joint_names(), msg->joint_names))
471  {
472  ROS_ERROR("Joint names from the controller don't match our joint names.");
473  return;
474  }
475 
476  // Checking for goal constraints
477  // Checks that we have ended inside the goal constraints and has motion stopped
478 
479  ROS_DEBUG("Checking goal constraints");
480  if (withinGoalConstraints(last_trajectory_state_map_[robot_id], current_traj_map_[robot_id], robot_id))
481  {
482  if (last_robot_status_)
483  {
484  // Additional check for motion stoppage since the controller goal may still
485  // be moving. The current robot driver calls a motion stop if it receives
486  // a new trajectory while it is still moving. If the driver is not publishing
487  // the motion state (i.e. old driver), this will still work, but it warns you.
488  if (last_robot_status_->in_motion.val == industrial_msgs::TriState::FALSE)
489  {
490  ROS_INFO("Inside goal constraints, stopped moving, return success for action");
491  active_goal_map_[robot_id].setSucceeded();
492  has_active_goal_map_[robot_id] = false;
493  }
494  else if (last_robot_status_->in_motion.val == industrial_msgs::TriState::UNKNOWN)
495  {
496  ROS_INFO("Inside goal constraints, return success for action");
497  ROS_WARN("Robot status in motion unknown, the robot driver node and controller code should be updated");
498  active_goal_map_[robot_id].setSucceeded();
499  has_active_goal_map_[robot_id] = false;
500  }
501  else
502  {
503  ROS_DEBUG("Within goal constraints but robot is still moving");
504  }
505  }
506  else
507  {
508  ROS_INFO("Inside goal constraints, return success for action");
509  ROS_WARN("Robot status is not being published the robot driver node and controller code should be updated");
510  active_goal_map_[robot_id].setSucceeded();
511  has_active_goal_map_[robot_id] = false;
512  }
513  }
514 }
515 
516 void JointTrajectoryAction::controllerStateCB(
517  const control_msgs::FollowJointTrajectoryFeedbackConstPtr &msg)
518 {
519  ROS_DEBUG("Checking controller state feedback");
520  last_trajectory_state_ = msg;
521  trajectory_state_recvd_ = true;
522 
523  if (!has_active_goal_)
524  {
525  ROS_DEBUG("No active goal, ignoring feedback");
526  return;
527  }
528  if (current_traj_.points.empty())
529  {
530  ROS_DEBUG("Current trajectory is empty, ignoring feedback");
531  return;
532  }
533 
534  if (!industrial_utils::isSimilar(all_joint_names_, msg->joint_names))
535  {
536  ROS_ERROR("Joint names from the controller don't match our joint names.");
537  return;
538  }
539 
540  // Checking for goal constraints
541  // Checks that we have ended inside the goal constraints and has motion stopped
542 
543  ROS_DEBUG("Checking goal constraints");
544  if (withinGoalConstraints(last_trajectory_state_, current_traj_))
545  {
546  if (last_robot_status_)
547  {
548  // Additional check for motion stoppage since the controller goal may still
549  // be moving. The current robot driver calls a motion stop if it receives
550  // a new trajectory while it is still moving. If the driver is not publishing
551  // the motion state (i.e. old driver), this will still work, but it warns you.
552  if (last_robot_status_->in_motion.val == industrial_msgs::TriState::FALSE)
553  {
554  ROS_INFO("Inside goal constraints, stopped moving, return success for action");
555  active_goal_.setSucceeded();
556  has_active_goal_ = false;
557  }
558  else if (last_robot_status_->in_motion.val == industrial_msgs::TriState::UNKNOWN)
559  {
560  ROS_INFO("Inside goal constraints, return success for action");
561  ROS_WARN("Robot status in motion unknown, the robot driver node and controller code should be updated");
562  active_goal_.setSucceeded();
563  has_active_goal_ = false;
564  }
565  else
566  {
567  ROS_DEBUG("Within goal constraints but robot is still moving");
568  }
569  }
570  else
571  {
572  ROS_INFO("Inside goal constraints, return success for action");
573  ROS_WARN("Robot status is not being published the robot driver node and controller code should be updated");
574  active_goal_.setSucceeded();
575  has_active_goal_ = false;
576  }
577  }
578 }
579 
580 void JointTrajectoryAction::abortGoal()
581 {
582  // Stops the controller.
583  trajectory_msgs::JointTrajectory empty;
584  pub_trajectory_command_.publish(empty);
585 
586  // Marks the current goal as aborted.
587  active_goal_.setAborted();
588  has_active_goal_ = false;
589 }
590 
591 void JointTrajectoryAction::abortGoal(int robot_id)
592 {
593  // Stops the controller.
594  motoman_msgs::DynamicJointTrajectory empty;
595  pub_trajectories_[robot_id].publish(empty);
596 
597  // Marks the current goal as aborted.
598  active_goal_map_[robot_id].setAborted();
599  has_active_goal_map_[robot_id] = false;
600 }
601 
602 bool JointTrajectoryAction::withinGoalConstraints(
603  const control_msgs::FollowJointTrajectoryFeedbackConstPtr &msg,
604  const trajectory_msgs::JointTrajectory & traj)
605 {
606  bool rtn = false;
607  if (traj.points.empty())
608  {
609  ROS_WARN("Empty joint trajectory passed to check goal constraints, return false");
610  rtn = false;
611  }
612  else
613  {
614  int last_point = traj.points.size() - 1;
615 
617  last_trajectory_state_->joint_names,
618  last_trajectory_state_->actual.positions, traj.joint_names,
619  traj.points[last_point].positions, goal_threshold_))
620  {
621  rtn = true;
622  }
623  else
624  {
625  rtn = false;
626  }
627  }
628  return rtn;
629 }
630 
631 bool JointTrajectoryAction::withinGoalConstraints(
632  const control_msgs::FollowJointTrajectoryFeedbackConstPtr &msg,
633  const trajectory_msgs::JointTrajectory & traj, int robot_id)
634 {
635  bool rtn = false;
636  if (traj.points.empty())
637  {
638  ROS_WARN("Empty joint trajectory passed to check goal constraints, return false");
639  rtn = false;
640  }
641  else
642  {
643  int last_point = traj.points.size() - 1;
644 
645  int group_number = robot_id;
646 
648  robot_groups_[group_number].get_joint_names(),
649  last_trajectory_state_map_[group_number]->actual.positions, traj.joint_names,
650  traj.points[last_point].positions, goal_threshold_))
651  {
652  rtn = true;
653  }
654  else
655  {
656  rtn = false;
657  }
658  }
659  return rtn;
660 }
661 
662 } // namespace joint_trajectory_action
663 } // namespace industrial_robot_client
664 
665 
bool getJointGroups(const std::string topic_param, std::map< int, RobotGroup > &robot_groups)
Parses multi-group joints from topic_param.
#define ROS_WARN(...)
void registerGoalCallback(boost::function< void(GoalHandle)> cb)
#define ROS_INFO(...)
static const double DEFAULT_GOAL_THRESHOLD_
The default goal joint threshold see(goal_threshold). Unit are joint specific (i.e. radians or meters).
bool isSimilar(std::vector< std::string > lhs, std::vector< std::string > rhs)
#define ROS_WARN_STREAM(args)
#define ROS_INFO_STREAM(args)
bool isWithinRange(const std::vector< double > &lhs, const std::vector< double > &rhs, double full_range)
static Time now()
#define ROS_ERROR(...)
#define ROS_DEBUG(...)


motoman_driver
Author(s): Jeremy Zoss (Southwest Research Institute), Ted Miller (MotoROS) (Yaskawa Motoman), Eric Marcil (MotoROS) (Yaskawa Motoman)
autogenerated on Sat May 8 2021 02:27:43