Sarafun Behavior Trees package  1
Behavior trees for the SARAFun project
 All Data Structures Namespaces Functions Variables Enumerations Enumerator
ExecuteAction.h
1 #ifndef __EXECUTE_ACTION__
2 #define __EXECUTE_ACTION__
3 
4 #include <ros/ros.h>
5 #include <behavior_tree_leaves/ActionTemplate.h>
6 #include <actionlib/client/simple_action_client.h>
7 
8 namespace sarafun {
16 template <class ActionClass, class ActionGoal>
17 class ExecuteAction : ActionTemplate {
18 public:
26  ExecuteAction(std::string node_name, std::string actionlib_name,
27  std::string bt_name);
28  virtual ~ExecuteAction();
29 
30  int executionRoutine();
31  void preemptionRoutine();
32 
33 protected:
40  virtual bool fillGoal(ActionGoal &goal) = 0;
41 
48  virtual double getTimeoutValue() = 0;
49 
57  bool fillParameter(std::string param_name, std::string &param_val);
58 
67  void fillParameter(std::string param_name, std::string def,
68  std::string &param_val);
69  void fillParameter(std::string param_name, double def, double &param_val);
70  void fillParameter(std::string param_name, int def, int &param_val);
71 
77  bool isSystemActive();
78 
79 private:
80  actionlib::SimpleActionClient<ActionClass> *action_client_;
81  ActionGoal goal_;
82  std::string action_name_;
83  ros::Time start_time_; // Current execution start time
84 };
85 
86 // Template classes "must" be implemented in the header files... -->
87 // http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file
88 
89 template <class ActionClass, class ActionGoal>
91  std::string node_name, std::string actionlib_name, std::string bt_name)
92  : ActionTemplate::ActionTemplate(bt_name) {
93  nh_ = ros::NodeHandle("~");
94  action_name_ = actionlib_name;
95  action_client_ = 0;
96 }
97 
98 template <class ActionClass, class ActionGoal>
100  delete action_client_;
101 }
102 
103 template <class ActionClass, class ActionGoal>
105  bool running;
106  if (nh_.hasParam("/sarafun/bt/running")) {
107  nh_.getParam("/sarafun/bt/running", running);
108 
109  if (running) {
110  return true;
111  }
112  } else {
113  ROS_WARN("The parameter /sarafun/bt/running must be set"
114  "for a BT action to run!");
115  }
116  return false;
117 }
118 
119 template <class ActionClass, class ActionGoal>
121  action_client_->cancelAllGoals();
122  delete action_client_;
123  action_client_ = 0;
124  ROS_WARN("The node %s was preempted", action_name_.c_str());
125 }
126 
127 template <class ActionClass, class ActionGoal>
129 
130  if (action_client_ == 0) // fresh call!
131  {
132  action_client_ = new actionlib::SimpleActionClient<ActionClass>(action_name_, true);
133  ROS_INFO("Action %s is waiting for the corresponding actionlib server!", action_name_.c_str());
134  bool active_server = action_client_->waitForServer(ros::Duration(2.0));
135  if (!active_server) {
136  ROS_ERROR("Actionlib server failed to start for action %s!",
137  action_name_.c_str());
138  delete action_client_;
139  action_client_ = 0;
140  return -1; // Failure
141  }
142  start_time_ = ros::Time::now();
143 
144  bool has_parameters = fillGoal(goal_);
145 
146  if (!has_parameters) {
147  ROS_ERROR("Failed to get parameters for action %s!", action_name_.c_str());
148  return -1; // Failure
149  }
150 
151  ROS_INFO("Sending goal from action: %s. Timeout value: %.2f", action_name_.c_str(), getTimeoutValue());
152  action_client_->sendGoal(goal_);
153  }
154 
155  if (!isSystemActive()) {
156  return 0; // Keep running
157  }
158 
159  bool finished = false, timeout = false;
160  if ((ros::Time::now() - start_time_).toSec() < getTimeoutValue())
161  {
162  actionlib::SimpleClientGoalState goal_state = action_client_->getState();
163  if (goal_state != actionlib::SimpleClientGoalState::ACTIVE && goal_state != actionlib::SimpleClientGoalState::PENDING)
164  {
165  finished = true;
166  }
167  }
168  else
169  {
170  timeout = true;
171  }
172 
173  if (finished) {
174  action_client_->cancelAllGoals(); // To be safe
175  actionlib::SimpleClientGoalState state = action_client_->getState();
176  ROS_INFO("Action finished: %s", state.toString().c_str());
177 
178  delete action_client_;
179  action_client_ = 0;
180  if (state == actionlib::SimpleClientGoalState::SUCCEEDED) {
181  return 1;
182  } else {
183  return -1;
184  }
185  } else {
186  if (timeout)
187  {
188  ROS_ERROR("Action %s timeout! Cancelling goals...", action_name_.c_str());
189  action_client_->cancelAllGoals();
190  delete action_client_;
191  action_client_ = 0;
192  return -1;
193  }
194  }
195 }
196 
197 template <class ActionClass, class ActionGoal>
199  std::string param_name, std::string &param_val) {
200  if (nh_.hasParam(param_name.c_str())) {
201  nh_.getParam(param_name.c_str(), param_val);
202  } else {
203  ROS_ERROR("%s not set!", param_name.c_str());
204  return false;
205  }
206  return true;
207 }
208 
209 template <class ActionClass, class ActionGoal>
211  std::string param_name, std::string def, std::string &param_val) {
212  if (nh_.hasParam(param_name.c_str())) {
213  nh_.getParam(param_name.c_str(), param_val);
214  } else {
215  ROS_WARN("Param '%s' not set. Using default: %s", param_name.c_str(),
216  def.c_str());
217  }
218 }
219 
220 template <class ActionClass, class ActionGoal>
222  std::string param_name, double def, double &param_val) {
223  if (nh_.hasParam(param_name.c_str())) {
224  nh_.getParam(param_name.c_str(), param_val);
225  } else {
226  ROS_WARN("Param '%s' not set. Using default: %.2f", param_name.c_str(),
227  def);
228  }
229 }
230 
231 template <class ActionClass, class ActionGoal>
233  std::string param_name, int def, int &param_val) {
234  if (nh_.hasParam(param_name.c_str())) {
235  nh_.getParam(param_name.c_str(), param_val);
236  } else {
237  ROS_WARN("Param '%s' not set. Using default: %d", param_name.c_str(),
238  def);
239  }
240 }
241 }
242 #endif
virtual bool fillGoal(ActionGoal &goal)=0
std::string action_name_
Definition: ExecuteAction.h:82
virtual double getTimeoutValue()=0
ExecuteAction(std::string node_name, std::string actionlib_name, std::string bt_name)
Definition: ExecuteAction.h:90
actionlib::SimpleActionClient< ActionClass > * action_client_
Definition: ExecuteAction.h:80
bool fillParameter(std::string param_name, std::string &param_val)