fsrobo_r_joint_trajectory_action.cpp
Go to the documentation of this file.
1 /*********************************************************************
2 * FSRobo-R Package BSDL
3 * ---------
4 * Copyright (C) 2019 FUJISOFT. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without modification,
7 * are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation and/or
12 * other materials provided with the distribution.
13 * 3. Neither the name of the copyright holder nor the names of its contributors
14 * may be used to endorse or promote products derived from this software without
15 * specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *********************************************************************/
28 
32 #include <industrial_utils/utils.h>
33 
34 namespace fsrobo_r_driver
35 {
36 namespace joint_trajectory_action
37 {
38 
41 
43  action_server_(node_, "joint_trajectory_action", boost::bind(&FSRoboRJointTrajectoryAction::goalCB, this, _1),
44  boost::bind(&FSRoboRJointTrajectoryAction::cancelCB, this, _1), false), has_active_goal_(false),
45  controller_alive_(false), has_moved_once_(false)
46 {
47  ros::NodeHandle pn("~");
48 
49  pn.param("constraints/goal_threshold", goal_threshold_, DEFAULT_GOAL_THRESHOLD_);
50 
51  if (!industrial_utils::param::getJointNames("controller_joint_names", "robot_description", joint_names_))
52  ROS_ERROR("Failed to initialize joint_names.");
53 
54  // The controller joint names parameter includes empty joint names for those joints not supported
55  // by the controller. These are removed since the trajectory action should ignore these.
56  std::remove(joint_names_.begin(), joint_names_.end(), std::string());
57  ROS_INFO_STREAM("Filtered joint names to " << joint_names_.size() << " joints");
58 
59  pub_trajectory_command_ = node_.advertise<trajectory_msgs::JointTrajectory>("joint_path_command", 1);
62 
64 
67 }
68 
70 {
71 }
72 
73 void FSRoboRJointTrajectoryAction::robotStatusCB(const industrial_msgs::RobotStatusConstPtr &msg)
74 {
75  last_robot_status_ = msg; //caching robot status for later use.
76  has_moved_once_ = has_moved_once_ ? true : (last_robot_status_->in_motion.val == industrial_msgs::TriState::TRUE);
77 
78  if (last_robot_status_->motion_possible.val == industrial_msgs::TriState::FALSE) {
79  if (has_active_goal_) {
80  ROS_WARN("Aborting goal because motion possible status is FALSE.");
81  abortGoal();
82  }
83  }
84 }
85 
87 {
88  // Some debug logging
90  {
91  ROS_DEBUG("Waiting for subscription to joint trajectory state");
92  }
93 
94  ROS_WARN("Trajectory state not received for %f seconds", WATCHDOG_PERIOD_);
95  controller_alive_ = false;
96 
97 
98  // Aborts the active goal if the controller does not appear to be active.
99  if (has_active_goal_)
100  {
101  // last_trajectory_state_ is null if the subscriber never makes a connection
103  {
104  ROS_WARN("Aborting goal because we have never heard a controller state message.");
105  }
106  else
107  {
109  "Aborting goal because we haven't heard from the controller in " << WATCHDOG_PERIOD_ << " seconds");
110  }
111 
112  abortGoal();
113  }
114 }
115 
117 {
118  ROS_INFO("Received new goal");
119 
120  // reject all goals as long as we haven't heard from the remote controller
121  if (!controller_alive_)
122  {
123  ROS_ERROR("Joint trajectory action rejected: waiting for (initial) feedback from controller");
124  control_msgs::FollowJointTrajectoryResult rslt;
125  rslt.error_code = control_msgs::FollowJointTrajectoryResult::INVALID_GOAL;
126  gh.setRejected(rslt, "Waiting for (initial) feedback from controller");
127 
128  // no point in continuing: already rejected
129  return;
130  }
131 
132  if (!gh.getGoal()->trajectory.points.empty())
133  {
134  if (industrial_utils::isSimilar(joint_names_, gh.getGoal()->trajectory.joint_names))
135  {
136 
137  // Cancels the currently active goal.
138  if (has_active_goal_)
139  {
140  ROS_WARN("Received new goal, canceling current goal");
141  abortGoal();
142  }
143 
144  gh.setAccepted();
145  active_goal_ = gh;
146  has_active_goal_ = true;
148  ros::Duration(active_goal_.getGoal()->trajectory.points.back().time_from_start.toSec() / 2.0);
149  has_moved_once_ = false;
150 
151  ROS_INFO("Publishing trajectory");
152 
153  current_traj_ = active_goal_.getGoal()->trajectory;
156  }
157  else {
158  ROS_WARN("Cancel publishing trajectory because of current position is goal");
159  }
160  }
161  else
162  {
163  ROS_ERROR("Joint trajectory action failing on invalid joints");
164  control_msgs::FollowJointTrajectoryResult rslt;
165  rslt.error_code = control_msgs::FollowJointTrajectoryResult::INVALID_JOINTS;
166  gh.setRejected(rslt, "Joint names do not match");
167  }
168  }
169  else
170  {
171  ROS_ERROR("Joint trajectory action failed on empty trajectory");
172  control_msgs::FollowJointTrajectoryResult rslt;
173  rslt.error_code = control_msgs::FollowJointTrajectoryResult::INVALID_GOAL;
174  gh.setRejected(rslt, "Empty trajectory");
175  }
176 
177  // Adding some informational log messages to indicate unsupported goal constraints
178  if (gh.getGoal()->goal_time_tolerance.toSec() > 0.0)
179  {
180  ROS_WARN_STREAM("Ignoring goal time tolerance in action goal, may be supported in the future");
181  }
182  if (!gh.getGoal()->goal_tolerance.empty())
183  {
185  "Ignoring goal tolerance in action, using paramater tolerance of " << goal_threshold_ << " instead");
186  }
187  if (!gh.getGoal()->path_tolerance.empty())
188  {
189  ROS_WARN_STREAM("Ignoring goal path tolerance, option not supported by ROS-Industrial drivers");
190  }
191 }
192 
194 {
195  ROS_DEBUG("Received action cancel request");
196  if (active_goal_ == gh)
197  {
198  // Stops the controller.
199  trajectory_msgs::JointTrajectory empty;
200  empty.joint_names = joint_names_;
202 
203  // Marks the current goal as canceled.
205  has_active_goal_ = false;
206  }
207  else
208  {
209  ROS_WARN("Active goal and goal cancel do not match, ignoring cancel request");
210  }
211 }
212 
213 void FSRoboRJointTrajectoryAction::controllerStateCB(const control_msgs::FollowJointTrajectoryFeedbackConstPtr &msg)
214 {
215  ROS_DEBUG("Checking controller state feedback");
217  controller_alive_ = true;
218 
221 
222  if (!has_active_goal_)
223  {
224  //ROS_DEBUG("No active goal, ignoring feedback");
225  return;
226  }
227  if (current_traj_.points.empty())
228  {
229  ROS_DEBUG("Current trajectory is empty, ignoring feedback");
230  return;
231  }
232 
233  if (!industrial_utils::isSimilar(joint_names_, msg->joint_names))
234  {
235  ROS_ERROR("Joint names from the controller don't match our joint names.");
236  return;
237  }
238 
240  {
241  ROS_DEBUG("Waiting to check for goal completion until halfway through trajectory");
242  return;
243  }
244 
245  // Checking for goal constraints
246  // Checks that we have ended inside the goal constraints and has motion stopped
247 
248  ROS_DEBUG("Checking goal constraints");
250  {
251  if (last_robot_status_)
252  {
253  // Additional check for motion stoppage since the controller goal may still
254  // be moving. The current robot driver calls a motion stop if it receives
255  // a new trajectory while it is still moving. If the driver is not publishing
256  // the motion state (i.e. old driver), this will still work, but it warns you.
257  if (last_robot_status_->in_motion.val == industrial_msgs::TriState::FALSE)
258  {
259  ROS_INFO("Inside goal constraints, stopped moving, return success for action");
261  has_active_goal_ = false;
262  }
263  else if (last_robot_status_->in_motion.val == industrial_msgs::TriState::UNKNOWN)
264  {
265  ROS_INFO("Inside goal constraints, return success for action");
266  ROS_WARN("Robot status in motion unknown, the robot driver node and controller code should be updated");
268  has_active_goal_ = false;
269  }
270  else
271  {
272  ROS_DEBUG("Within goal constraints but robot is still moving");
273  }
274  }
275  else
276  {
277  ROS_INFO("Inside goal constraints, return success for action");
278  ROS_WARN("Robot status is not being published the robot driver node and controller code should be updated");
280  has_active_goal_ = false;
281  }
282  }
283 }
284 
285 bool FSRoboRJointTrajectoryAction::cancelMotionCB(std_srvs::EmptyRequest &req, std_srvs::EmptyResponse &res)
286 {
287  ROS_INFO("cancelMotionCB: called");
288 
289  // Stops the controller.
290  trajectory_msgs::JointTrajectory empty;
292 
293  // Marks the current goal as succeeded.
295  has_active_goal_ = false;
296 
297  return true;
298 }
299 
301 {
302  // Stops the controller.
303  trajectory_msgs::JointTrajectory empty;
305 
306  // Marks the current goal as aborted.
308  has_active_goal_ = false;
309 }
310 
311 bool FSRoboRJointTrajectoryAction::withinGoalConstraints(const control_msgs::FollowJointTrajectoryFeedbackConstPtr &msg,
312  const trajectory_msgs::JointTrajectory & traj)
313 {
314  bool rtn = false;
315  if (traj.points.empty())
316  {
317  ROS_WARN("Empty joint trajectory passed to check goal constraints, return false");
318  rtn = false;
319  }
320  else
321  {
322  int last_point = traj.points.size() - 1;
323 
325  last_trajectory_state_->actual.positions, traj.joint_names,
326  traj.points[last_point].positions, goal_threshold_))
327  {
328  rtn = true;
329  }
330  else
331  {
332  rtn = false;
333  }
334  }
335  return rtn;
336 }
337 
338 }
339 }
340 
ros::Publisher pub_trajectory_command_
Publishes desired trajectory (typically to the robot driver)
bool getJointNames(const std::string joint_list_param, const std::string urdf_param, std::vector< std::string > &joint_names)
void publish(const boost::shared_ptr< M > &message) const
bool withinGoalConstraints(const control_msgs::FollowJointTrajectoryFeedbackConstPtr &msg, const trajectory_msgs::JointTrajectory &traj)
Controller status callback (executed when robot status message received)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
void stop()
void setRejected(const Result &result=Result(), const std::string &text=std::string(""))
void start()
bool has_moved_once_
Indicates that the robot has been in a moving state at least once since starting the current active t...
boost::shared_ptr< const Goal > getGoal() const
industrial_msgs::RobotStatusConstPtr last_robot_status_
Cache of the last subscribed status message.
bool controller_alive_
Controller was alive during the last watchdog interval.
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
bool cancelMotionCB(std_srvs::EmptyRequest &req, std_srvs::EmptyResponse &res)
Cancel motion callback (executed when cancel_motion service is called)
#define ROS_WARN(...)
void setCanceled(const Result &result=Result(), const std::string &text=std::string(""))
void abortGoal()
Aborts the current action goal and sends a stop command (empty message) to the robot driver...
void goalCB(JointTractoryActionServer::GoalHandle gh)
Action server goal callback method.
void setAccepted(const std::string &text=std::string(""))
void setSucceeded(const Result &result=Result(), const std::string &text=std::string(""))
control_msgs::FollowJointTrajectoryFeedbackConstPtr last_trajectory_state_
Cache of the last subscribed feedback message.
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
void robotStatusCB(const industrial_msgs::RobotStatusConstPtr &msg)
Controller status callback (executed when robot status message received)
double goal_threshold_
The goal joint threshold used for determining if a robot is near it final destination. A single value is used for all joints.
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
ros::Subscriber sub_robot_status_
Subscribes to the robot status (typically published by the robot driver).
bool isSimilar(std::vector< std::string > lhs, std::vector< std::string > rhs)
void controllerStateCB(const control_msgs::FollowJointTrajectoryFeedbackConstPtr &msg)
Controller state callback (executed when feedback message received)
#define ROS_WARN_STREAM(args)
std::vector< std::string > joint_names_
The joint names associated with the robot the action is interfacing with. The joint names must be the...
void setAborted(const Result &result=Result(), const std::string &text=std::string(""))
trajectory_msgs::JointTrajectory current_traj_
Cache of the current active trajectory.
#define ROS_INFO_STREAM(args)
ros::Time time_to_check_
Time at which to start checking for completion of current goal, if one is active. ...
ros::Timer watchdog_timer_
Watchdog time used to fail the action request if the robot driver is not responding.
void watchdog(const ros::TimerEvent &e)
Watch dog callback, used to detect robot driver failures.
bool isWithinRange(const std::vector< double > &lhs, const std::vector< double > &rhs, double full_range)
void cancelCB(JointTractoryActionServer::GoalHandle gh)
Action server cancel callback method.
static Time now()
static const double DEFAULT_GOAL_THRESHOLD_
The default goal joint threshold see(goal_threshold). Unit are joint specific (i.e. radians or meters).
#define ROS_ERROR(...)
JointTractoryActionServer::GoalHandle active_goal_
Cache of the current active goal.
ros::Subscriber sub_trajectory_state_
Subscribes to trajectory feedback (typically published by the robot driver).
#define ROS_DEBUG(...)


fsrobo_r_driver
Author(s): F-ROSROBO
autogenerated on Sun Feb 9 2020 03:58:29