cob_trajectory_controller.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 
18 #include "ros/ros.h"
19 #include <std_msgs/String.h>
20 #include <std_msgs/Float64MultiArray.h>
21 #include <sensor_msgs/JointState.h>
22 #include <control_msgs/JointTrajectoryControllerState.h>
24 #include <control_msgs/FollowJointTrajectoryAction.h>
25 
27 // ROS service includes
28 #include <std_srvs/Trigger.h>
29 #include <cob_srvs/SetString.h>
30 #include <cob_srvs/SetFloat.h>
31 
32 
33 #define HZ 100
34 
36 {
37 private:
40 
48 
50 
51  std::string action_name_;
53  std::vector<std::string> JointNames_;
54  bool executing_;
55  bool failure_;
56  bool rejected_;
57  bool preemted_;
58  int DOF;
60 
63  trajectory_msgs::JointTrajectory traj_;
64  trajectory_msgs::JointTrajectory traj_2_;
65  std::vector<double> q_current, startposition_, joint_distance_;
66 
67 public:
68 
70  as_(n_, "joint_trajectory_controller/follow_joint_trajectory", boost::bind(&cob_trajectory_controller_node::executeFollowTrajectory, this, _1), false),
71  action_name_("follow_joint_trajectory")
72  {
73  joint_vel_pub_ = n_.advertise<std_msgs::Float64MultiArray>("joint_group_velocity_controller/command", 1);
74  controller_state_ = n_.subscribe("joint_trajectory_controller/state", 1, &cob_trajectory_controller_node::state_callback, this);
75  operation_mode_ = n_.subscribe("driver/current_operationmode", 1, &cob_trajectory_controller_node::operationmode_callback, this);
76  srvServer_Stop_ = n_.advertiseService("driver/stop", &cob_trajectory_controller_node::srvCallback_Stop, this);
77  srvServer_SetVel_ = n_.advertiseService("driver/set_joint_velocity", &cob_trajectory_controller_node::srvCallback_setVel, this);
78  srvServer_SetAcc_ = n_.advertiseService("driver/set_joint_acceleration", &cob_trajectory_controller_node::srvCallback_setAcc, this);
79  srvClient_SetOperationMode = n_.serviceClient<cob_srvs::SetString>("driver/set_operation_mode");
80  while(!srvClient_SetOperationMode.exists())
81  {
82  ROS_INFO("Waiting for operationmode service to become available");
83  sleep(1);
84  }
85  executing_ = false;
86  failure_ = false;
87  rejected_ = false;
88  preemted_ = false;
89  watchdog_counter = 0;
90  current_operation_mode_ = "undefined";
91  double PTPvel = 0.7;
92  double PTPacc = 0.2;
93  double maxError = 0.7;
94  double overlap_time = 0.4;
95  velocity_timeout_ = 2.0;
96  DOF = 7;
97  // get JointNames from parameter server
98  ROS_INFO("getting JointNames from parameter server: %s", n_private_.getNamespace().c_str());
99  if (n_private_.hasParam("joint_names"))
100  {
101  n_private_.getParam("joint_names", JointNames_);
102  }
103  else
104  {
105  ROS_ERROR("Parameter 'joint_names' not set");
106  }
107  DOF = JointNames_.size();
108 
109  if (n_private_.hasParam("ptp_vel"))
110  {
111  n_private_.getParam("ptp_vel", PTPvel);
112  }
113  if (n_private_.hasParam("ptp_acc"))
114  {
115  n_private_.getParam("ptp_acc", PTPacc);
116  }
117  if (n_private_.hasParam("max_error"))
118  {
119  n_private_.getParam("max_error", maxError);
120  }
121  if (n_private_.hasParam("overlap_time"))
122  {
123  n_private_.getParam("overlap_time", overlap_time);
124  }
125  if (n_private_.hasParam("operation_mode"))
126  {
127  n_private_.getParam("operation_mode", current_operation_mode_);
128  }
129  q_current.resize(DOF);
130  ROS_INFO("starting controller with DOF: %d PTPvel: %f PTPAcc: %f maxError %f", DOF, PTPvel, PTPacc, maxError);
131  traj_generator_ = new genericArmCtrl(DOF, PTPvel, PTPacc, maxError);
132  traj_generator_->overlap_time = overlap_time;
133 
134  as_.start();
135  }
136 
137  double getFrequency()
138  {
139  double frequency;
140  if (n_private_.hasParam("frequency"))
141  {
142  n_private_.getParam("frequency", frequency);
143  ROS_INFO("Setting controller frequency to %f HZ", frequency);
144  }
145  else
146  {
147  frequency = 100; //Hz
148  ROS_WARN("Parameter 'frequency' not available, setting to default value: %f Hz", frequency);
149  }
150  return frequency;
151  }
152 
153  bool srvCallback_Stop(std_srvs::Trigger::Request &req, std_srvs::Trigger::Response &res)
154  {
155  ROS_INFO("Stopping trajectory controller.");
156 
157  // stop trajectory controller
158  executing_ = false;
159  res.success = true;
160  traj_generator_->isMoving = false;
161  failure_ = true;
162  return true;
163  }
164 
165  bool srvCallback_setVel(cob_srvs::SetFloat::Request &req, cob_srvs::SetFloat::Response &res)
166  {
167  ROS_INFO("Setting velocity to %f", req.data);
168  traj_generator_->SetPTPvel(req.data);
169  res.success = true;
170  return true;
171  }
172 
173  bool srvCallback_setAcc(cob_srvs::SetFloat::Request &req, cob_srvs::SetFloat::Response &res)
174  {
175  ROS_INFO("Setting acceleration to %f", req.data);
176  traj_generator_->SetPTPacc(req.data);
177  res.success = true;
178  return true;
179  }
180 
181  void operationmode_callback(const std_msgs::StringPtr& message)
182  {
183  current_operation_mode_ = message->data;
184  }
185 
186  void state_callback(const control_msgs::JointTrajectoryControllerStatePtr& message)
187  {
188  std::vector<double> positions = message->actual.positions;
189  for(unsigned int i = 0; i < positions.size(); i++)
190  {
191  q_current[i] = positions[i];
192  }
193  }
194 
195  void spawnTrajector(trajectory_msgs::JointTrajectory trajectory)
196  {
197  if(!executing_ || preemted_)
198  {
199  //set component to velocity mode
200  cob_srvs::SetString opmode;
201  opmode.request.data = "velocity";
202  srvClient_SetOperationMode.call(opmode);
203  ros::Time begin = ros::Time::now();
204  while(current_operation_mode_ != "velocity")
205  {
206  ROS_INFO("waiting for component to go to velocity mode");
207  usleep(100000);
208  //add timeout and set action to rejected
209  if((ros::Time::now() - begin).toSec() > velocity_timeout_)
210  {
211  rejected_ = true;
212  return;
213  }
214  }
215 
216  std::vector<double> traj_start;
217  if(preemted_ == true) //Calculate trajectory for runtime modification of trajectories
218  {
219  ROS_INFO("There is a old trajectory currently running");
220  traj_start = traj_generator_->last_q;
221  trajectory_msgs::JointTrajectory temp_traj;
222  temp_traj = trajectory;
223  //Insert the saved point as first point of trajectory, then generate SPLINE trajectory
224  trajectory_msgs::JointTrajectoryPoint p;
225  p.positions.resize(DOF);
226  p.velocities.resize(DOF);
227  p.accelerations.resize(DOF);
228  for(int i = 0; i<DOF; i++)
229  {
230  p.positions.at(i) = traj_start.at(i);
231  p.velocities.at(i) = 0.0;
232  p.accelerations.at(i) = 0.0;
233  }
234  std::vector<trajectory_msgs::JointTrajectoryPoint>::iterator it;
235  it = temp_traj.points.begin();
236  temp_traj.points.insert(it,p);
237  //Now insert the current as first point of trajectory, then generate SPLINE trajectory
238  for(int i = 0; i<DOF; i++)
239  {
240  p.positions.at(i) = traj_generator_->last_q1.at(i);
241  p.velocities.at(i) = 0.0;
242  p.accelerations.at(i) = 0.0;
243  }
244  it = temp_traj.points.begin();
245  temp_traj.points.insert(it,p);
246  for(int i = 0; i<DOF; i++)
247  {
248  p.positions.at(i) = traj_generator_->last_q2.at(i);
249  p.velocities.at(i) = 0.0;
250  p.accelerations.at(i) = 0.0;
251  }
252  it = temp_traj.points.begin();
253  temp_traj.points.insert(it,p);
254  for(int i = 0; i<DOF; i++)
255  {
256  p.positions.at(i) = traj_generator_->last_q3.at(i);
257  p.velocities.at(i) = 0.0;
258  p.accelerations.at(i) = 0.0;
259  }
260  it = temp_traj.points.begin();
261  temp_traj.points.insert(it,p);
262  for(int i = 0; i<DOF; i++)
263  {
264  p.positions.at(i) = q_current.at(i);
265  p.velocities.at(i) = 0.0;
266  p.accelerations.at(i) = 0.0;
267  }
268  it = temp_traj.points.begin();
269  temp_traj.points.insert(it,p);
270  traj_generator_->isMoving = false ;
271  traj_generator_->moveTrajectory(temp_traj, traj_start);
272  }
273  else //Normal calculation of trajectories
274  {
275  traj_start = q_current;
276  trajectory_msgs::JointTrajectory temp_traj;
277  temp_traj = trajectory;
278  if(temp_traj.points.size() == 1)
279  {
280  traj_generator_->isMoving = false ;
281  traj_generator_->moveThetas(temp_traj.points[0].positions, traj_start);
282  }
283  else
284  {
285  //Insert the current point as first point of trajectory, then generate SPLINE trajectory
286  trajectory_msgs::JointTrajectoryPoint p;
287  p.positions.resize(DOF);
288  p.velocities.resize(DOF);
289  p.accelerations.resize(DOF);
290  for(int i = 0; i<DOF; i++)
291  {
292  p.positions.at(i) = traj_start.at(i);
293  p.velocities.at(i) = 0.0;
294  p.accelerations.at(i) = 0.0;
295  }
296  std::vector<trajectory_msgs::JointTrajectoryPoint>::iterator it;
297  it = temp_traj.points.begin();
298  temp_traj.points.insert(it,p);
299  traj_generator_->isMoving = false ;
300  traj_generator_->moveTrajectory(temp_traj, traj_start);
301  }
302  }
303 
304  executing_ = true;
305  startposition_ = q_current;
306  preemted_ = false;
307 
308  }
309  else //suspend current movement and start new one
310  {
311  }
312  while(executing_)
313  {
314  if(!preemted_)
315  {
316  usleep(1000);
317  }
318  else
319  {
320  return;
321  }
322  }
323  }
324 
325 
326  void executeFollowTrajectory(const control_msgs::FollowJointTrajectoryGoalConstPtr &goal)
327  {
328  ROS_INFO("Received new goal trajectory with %lu points",goal->trajectory.points.size());
329  spawnTrajector(goal->trajectory);
330  // only set to succeeded if component could reach position. this is currently not the care for e.g. by emergency stop, hardware error or exceeds limit.
331  if(rejected_)
332  as_.setAborted(); //setRejected not implemented in simpleactionserver ?
333  else
334  {
335  if(failure_)
336  as_.setAborted();
337  else
338  as_.setSucceeded();
339  }
340  rejected_ = false;
341  failure_ = false;
342  }
343 
344  void run()
345  {
346  if(executing_)
347  {
348  failure_ = false;
349  watchdog_counter = 0;
350  if (!ros::ok() || current_operation_mode_ != "velocity")
351  {
352  // set the action state to preempted
353  executing_ = false;
354  traj_generator_->isMoving = false;
355  failure_ = true;
356  return;
357  }
358  if (as_.isPreemptRequested())
359  {
360  failure_ = true;
361  preemted_ = true;
362  executing_ = false;
363  traj_generator_->isMoving = false;
364  ROS_INFO("Preempted trajectory action");
365  return;
366  }
367  std::vector<double> des_vel;
368  if(traj_generator_->step(q_current, des_vel))
369  {
370  if(!traj_generator_->isMoving) //Finished trajectory
371  {
372  executing_ = false;
373  preemted_ = false;
374  }
375  std_msgs::Float64MultiArray target_joint_vel;
376  for(int i=0; i<DOF; i++)
377  {
378  target_joint_vel.data.push_back(des_vel.at(i));
379  }
380 
381  //send everything
382  joint_vel_pub_.publish(target_joint_vel);
383  }
384  else
385  {
386  ROS_INFO("An controller error occured!");
387  failure_ = true;
388  executing_ = false;
389  }
390  }
391  else
392  { //WATCHDOG TODO: don't always send
393  if(watchdog_counter < 10)
394  {
395  std_msgs::Float64MultiArray target_joint_vel;
396  for(int i=0; i<DOF; i++)
397  {
398  target_joint_vel.data.push_back(0.0);
399  }
400  joint_vel_pub_.publish(target_joint_vel);
401  }
402  watchdog_counter++;
403  }
404  }
405 
406 };
407 
408 
409 
410 int main(int argc, char ** argv)
411 {
412  ros::init(argc, argv, "cob_trajectory_controller");
413 
415 
417  double frequency = tm.getFrequency();
418 
419  ros::Rate loop_rate(frequency);
420  while (ros::ok())
421  {
422  tm.run();
423  ros::spinOnce();
424  loop_rate.sleep();
425  }
426 }
427 
428 
429 
ServiceClient serviceClient(const std::string &service_name, bool persistent=false, const M_string &header_values=M_string())
void SetPTPvel(double vel)
void publish(const boost::shared_ptr< M > &message) const
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
bool srvCallback_setVel(cob_srvs::SetFloat::Request &req, cob_srvs::SetFloat::Response &res)
void executeFollowTrajectory(const control_msgs::FollowJointTrajectoryGoalConstPtr &goal)
std::vector< double > last_q
bool step(std::vector< double > current_pos, std::vector< double > &desired_vel)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
bool call(MReq &req, MRes &res)
bool moveThetas(std::vector< double > conf_goal, std::vector< double > conf_current)
Will move the component to a goal configuration in Joint Space.
trajectory_msgs::JointTrajectory traj_2_
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
#define ROS_WARN(...)
std::vector< std::string > JointNames_
void setSucceeded(const Result &result=Result(), const std::string &text=std::string(""))
bool moveTrajectory(trajectory_msgs::JointTrajectory pfad, std::vector< double > conf_current)
trajectory_msgs::JointTrajectory traj_
int main(int argc, char **argv)
void spawnTrajector(trajectory_msgs::JointTrajectory trajectory)
#define ROS_INFO(...)
ROSCPP_DECL bool ok()
const std::string & getNamespace() const
std::vector< double > last_q2
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
bool sleep()
void SetPTPacc(double acc)
void setAborted(const Result &result=Result(), const std::string &text=std::string(""))
void state_callback(const control_msgs::JointTrajectoryControllerStatePtr &message)
bool srvCallback_Stop(std_srvs::Trigger::Request &req, std_srvs::Trigger::Response &res)
bool getParam(const std::string &key, std::string &s) const
actionlib::SimpleActionServer< control_msgs::FollowJointTrajectoryAction > as_
std::vector< double > last_q3
static Time now()
bool hasParam(const std::string &key) const
void operationmode_callback(const std_msgs::StringPtr &message)
bool srvCallback_setAcc(cob_srvs::SetFloat::Request &req, cob_srvs::SetFloat::Response &res)
ROSCPP_DECL void spinOnce()
#define ROS_ERROR(...)
std::vector< double > last_q1


cob_trajectory_controller
Author(s): Alexander Bubeck
autogenerated on Thu Apr 8 2021 02:39:55