joint_spline_trajectory_action_controller.cpp
Go to the documentation of this file.
1 
29 #include <controller_manager_msgs/ListControllers.h>
30 #include <sr_utilities/getJointState.h>
31 #include <std_msgs/Float64.h>
32 #include <sr_robot_msgs/sendupdate.h>
33 
34 #include <map>
35 #include <string>
36 #include <vector>
37 
38 namespace shadowrobot
39 {
40 // These functions are pulled from the spline_smoother package.
41 // They've been moved here to avoid depending on packages that aren't
42 // mature yet.
43  static inline void generatePowers(int n, double x, double *powers)
44  {
45  powers[0] = 1.0;
46 
47  for (int i = 1; i <= n; i++)
48  {
49  powers[i] = powers[i - 1] * x;
50  }
51  }
52 
53  static void getQuinticSplineCoefficients(double start_pos, double start_vel, double start_acc,
54  double end_pos, double end_vel, double end_acc, double time,
55  std::vector<double> &coefficients)
56  {
57  coefficients.resize(6);
58 
59  if (time == 0.0)
60  {
61  coefficients[0] = end_pos;
62  coefficients[1] = end_vel;
63  coefficients[2] = 0.5 * end_acc;
64  coefficients[3] = 0.0;
65  coefficients[4] = 0.0;
66  coefficients[5] = 0.0;
67  }
68  else
69  {
70  double T[6];
71  generatePowers(5, time, T);
72 
73  coefficients[0] = start_pos;
74  coefficients[1] = start_vel;
75  coefficients[2] = 0.5 * start_acc;
76  coefficients[3] = (-20.0 * start_pos + 20.0 * end_pos - 3.0 * start_acc * T[2] + end_acc * T[2] -
77  12.0 * start_vel * T[1] - 8.0 * end_vel * T[1]) / (2.0 * T[3]);
78  coefficients[4] = (30.0 * start_pos - 30.0 * end_pos + 3.0 * start_acc * T[2] - 2.0 * end_acc * T[2] +
79  16.0 * start_vel * T[1] + 14.0 * end_vel * T[1]) / (2.0 * T[4]);
80  coefficients[5] = (-12.0 * start_pos + 12.0 * end_pos - start_acc * T[2] + end_acc * T[2] -
81  6.0 * start_vel * T[1] - 6.0 * end_vel * T[1]) / (2.0 * T[5]);
82  }
83  }
84 
88  static void sampleQuinticSpline(const std::vector<double> &coefficients, double time,
89  double &position, double &velocity, double &acceleration)
90  {
91  // create powers of time:
92  double t[6];
93  generatePowers(5, time, t);
94 
95  position = t[0] * coefficients[0] +
96  t[1] * coefficients[1] +
97  t[2] * coefficients[2] +
98  t[3] * coefficients[3] +
99  t[4] * coefficients[4] +
100  t[5] * coefficients[5];
101 
102  velocity = t[0] * coefficients[1] +
103  2.0 * t[1] * coefficients[2] +
104  3.0 * t[2] * coefficients[3] +
105  4.0 * t[3] * coefficients[4] +
106  5.0 * t[4] * coefficients[5];
107 
108  acceleration = 2.0 * t[0] * coefficients[2] +
109  6.0 * t[1] * coefficients[3] +
110  12.0 * t[2] * coefficients[4] +
111  20.0 * t[3] * coefficients[5];
112  }
113 
114  static void getCubicSplineCoefficients(double start_pos, double start_vel,
115  double end_pos, double end_vel, double time, std::vector<double> &coefficients)
116  {
117  coefficients.resize(4);
118 
119  if (time == 0.0)
120  {
121  coefficients[0] = end_pos;
122  coefficients[1] = end_vel;
123  coefficients[2] = 0.0;
124  coefficients[3] = 0.0;
125  }
126  else
127  {
128  double T[4];
129  generatePowers(3, time, T);
130 
131  coefficients[0] = start_pos;
132  coefficients[1] = start_vel;
133  coefficients[2] = (-3.0 * start_pos + 3.0 * end_pos - 2.0 * start_vel * T[1] - end_vel * T[1]) / T[2];
134  coefficients[3] = (2.0 * start_pos - 2.0 * end_pos + start_vel * T[1] + end_vel * T[1]) / T[3];
135  }
136  }
137 
139  nh_tilde("~"), use_sendupdate(false)
140  {
141  action_server = boost::shared_ptr<JTAS>(new JTAS("/r_arm_controller/joint_trajectory_action",
143  this, _1),
144  false));
145  std::vector<std::string> joint_labels;
146 
147  // This the internal order of the joints
148  joint_labels.push_back("ShoulderJRotate");
149  joint_labels.push_back("ShoulderJSwing");
150  joint_labels.push_back("ElbowJSwing");
151  joint_labels.push_back("ElbowJRotate");
152  joint_labels.push_back("WRJ2");
153  joint_labels.push_back("WRJ1");
154 
155  // fillup a joint_state_idx_map
156  for (unsigned int i = 0; i < joint_labels.size(); i++)
157  {
158  joint_state_idx_map[joint_labels[i]] = i;
159  }
160 
161  // look for controllers and build controller name to joint map
162  if (ros::service::waitForService("controller_manager/list_controllers", 20000))
163  {
164  use_sendupdate = false;
165  ros::ServiceClient controller_list_client = nh.serviceClient<controller_manager_msgs::ListControllers>(
166  "controller_manager/list_controllers");
167  controller_manager_msgs::ListControllers controller_list;
168  std::string controlled_joint_name;
169 
170  // query the list
171  controller_list_client.call(controller_list);
172  // build the map
173  for (unsigned int i = 0; i < controller_list.response.controller.size(); i++)
174  {
175  if (controller_list.response.controller[i].state == "running")
176  {
177  if (nh.getParam("/" + controller_list.response.controller[i].name + "/joint", controlled_joint_name))
178  {
179  ROS_DEBUG("controller %d:%s controls joint %s\n", i, controller_list.response.controller[i].name.c_str(),
180  controlled_joint_name.c_str());
181  jointControllerMap[controlled_joint_name] = controller_list.response.controller[i].name;
182  }
183  }
184  }
185 
186  // build controller publisher to joint map
187  for (unsigned int i = 0; i < joint_labels.size(); i++)
188  {
189  std::string controller_name = jointControllerMap[joint_labels[i]];
190 
191  if (controller_name.compare("") != 0) // if exist, set idx to controller number + 1
192  {
193  controller_publishers.push_back(
194  nh.advertise<std_msgs::Float64>("/" + jointControllerMap[joint_labels[i]] + "/command", 2));
195  // we want the index to be above zero all the time
196  jointPubIdxMap[joint_labels[i]] = controller_publishers.size();
197  }
198  else // else put a zero in order to detect when this is empty
199  {
200  ROS_WARN("Could not find a controller for joint %s", joint_labels[i].c_str());
201  jointPubIdxMap[joint_labels[i]] = 0; // we want the index to be above zero all the time
202  }
203  }
204  }
205  else
206  {
207  ROS_WARN("controller_manager not found, switching back to sendupdates");
208  use_sendupdate = true;
209  sr_arm_target_pub = nh.advertise<sr_robot_msgs::sendupdate>("/sr_arm/sendupdate", 2);
210  sr_hand_target_pub = nh.advertise<sr_robot_msgs::sendupdate>("/srh/sendupdate", 2);
211  }
212 
213  ROS_INFO("waiting for getJointState");
214  if (ros::service::waitForService("getJointState", 20000))
215  {
216  // open persistent link to joint_state service
217  joint_state_client = nh.serviceClient<sr_utilities::getJointState>("getJointState", true);
218  }
219  else
220  {
221  ROS_ERROR("Cannot access service: Check if joint_state service is launched");
222  ros::shutdown();
223  exit(-1);
224  }
225  ROS_INFO("Got getJointState");
226  joint_names_ = joint_labels;
227 
228  q.resize(joint_names_.size());
229  qd.resize(joint_names_.size());
230  qdd.resize(joint_names_.size());
231 
232  desired_joint_state_pusblisher = nh.advertise<sensor_msgs::JointState>("/desired_joint_states", 2);
233 
235  ROS_INFO("Listening to commands");
236 
237  action_server->start();
238  ROS_INFO("Action server started");
239  }
240 
242  {
243  sr_utilities::getJointState getState;
244  sensor_msgs::JointState joint_state_msg;
245  if (joint_state_client.call(getState))
246  {
247  joint_state_msg = getState.response.joint_state;
248  if (joint_state_msg.name.size() > 0)
249  {
250  // fill up the lookup map with updated positions
251  for (unsigned int i = 0; i < joint_state_msg.name.size(); i++)
252  {
253  joint_state_map[joint_state_msg.name[i]] = joint_state_msg.position[i];
254  }
255  }
256  }
257  }
258 
259  bool JointTrajectoryActionController::getPosition(std::string joint_name, double &position)
260  {
261  std::map<std::string, double>::iterator iter = joint_state_map.find(joint_name);
262  if (iter != joint_state_map.end())
263  {
264  position = iter->second;
265  return true;
266  }
267  else
268  {
269  ROS_ERROR("Joint %s not found", joint_name.c_str());
270  return false;
271  }
272  }
273 
274 
275  void JointTrajectoryActionController::execute_trajectory(const control_msgs::FollowJointTrajectoryGoalConstPtr &goal)
276  {
277  bool success = true;
278 
279  ros::Time time = ros::Time::now() - ros::Duration(0.05);
280  last_time_ = time;
281  ROS_DEBUG("Figuring out new trajectory at %.3lf, with data from %.3lf",
282  time.toSec(), goal->trajectory.header.stamp.toSec());
283 
285  SpecifiedTrajectory &traj = *new_traj_ptr;
286 
287 
288  // Finds the end conditions of the final segment
289  std::vector<double> prev_positions(joint_names_.size());
290  std::vector<double> prev_velocities(joint_names_.size());
291  std::vector<double> prev_accelerations(joint_names_.size());
292 
294 
295  ROS_DEBUG("Initial conditions for new set of splines:");
296  for (size_t i = 0; i < joint_names_.size(); ++i)
297  {
298  double position;
299  if (getPosition(joint_names_[i], position))
300  {
301  prev_positions[joint_state_idx_map[joint_names_[i]]] = position;
302  }
303  else
304  {
305  ROS_ERROR("Cannot get joint_state, not executing trajectory");
306  return;
307  }
308  prev_velocities[i] = 0.0;
309  prev_accelerations[i] = 0.0;
310 
311  ROS_DEBUG(" %.2lf, %.2lf, %.2lf (%s)", prev_positions[i], prev_velocities[i],
312  prev_accelerations[i], joint_names_[i].c_str());
313  }
314  // ------ Tacks on the new segments
315  std::vector<double> positions;
316  std::vector<double> velocities;
317  std::vector<double> accelerations;
318 
319  std::vector<double> durations(goal->trajectory.points.size());
320  if (goal->trajectory.points.size() > 0)
321  {
322  durations[0] = goal->trajectory.points[0].time_from_start.toSec();
323  }
324  for (size_t i = 1; i < goal->trajectory.points.size(); ++i)
325  {
326  durations[i] = (goal->trajectory.points[i].time_from_start -
327  goal->trajectory.points[i - 1].time_from_start).toSec();
328  }
329 
330  // no continuous joints so do not check if we should wrap
331 
332  // extract the traj
333  for (size_t i = 0; i < goal->trajectory.points.size(); ++i)
334  {
335  Segment seg;
336 
337  if (goal->trajectory.header.stamp == ros::Time(0.0))
338  {
339  seg.start_time = (time + goal->trajectory.points[i].time_from_start).toSec() - durations[i];
340  }
341  else
342  {
343  seg.start_time =
344  (goal->trajectory.header.stamp + goal->trajectory.points[i].time_from_start).toSec() - durations[i];
345  }
346  seg.duration = durations[i];
347  seg.splines.resize(joint_names_.size());
348 
349  // Checks that the incoming segment has the right number of elements.
350  if (goal->trajectory.points[i].accelerations.size() != 0 &&
351  goal->trajectory.points[i].accelerations.size() != joint_names_.size())
352  {
353  ROS_ERROR("Command point %d has %d elements for the accelerations", static_cast<int>(i),
354  static_cast<int>(goal->trajectory.points[i].accelerations.size()));
355  return;
356  }
357  if (goal->trajectory.points[i].velocities.size() != 0 &&
358  goal->trajectory.points[i].velocities.size() != joint_names_.size())
359  {
360  ROS_ERROR("Command point %d has %d elements for the velocities", static_cast<int>(i),
361  static_cast<int>(goal->trajectory.points[i].velocities.size()));
362  return;
363  }
364  if (goal->trajectory.points[i].positions.size() != joint_names_.size())
365  {
366  ROS_ERROR("Command point %d has %d elements for the positions", static_cast<int>(i),
367  static_cast<int>(goal->trajectory.points[i].positions.size()));
368  return;
369  }
370 
371  // Re-orders the joints in the command to match the internal joint order.
372  accelerations.resize(goal->trajectory.points[i].accelerations.size());
373  velocities.resize(goal->trajectory.points[i].velocities.size());
374  positions.resize(goal->trajectory.points[i].positions.size());
375  for (size_t j = 0; j < goal->trajectory.joint_names.size(); ++j)
376  {
377  if (!accelerations.empty())
378  {
379  accelerations[joint_state_idx_map[goal->trajectory.joint_names[j]]] =
380  goal->trajectory.points[i].accelerations[j];
381  }
382  if (!velocities.empty())
383  {
384  velocities[joint_state_idx_map[goal->trajectory.joint_names[j]]] = goal->trajectory.points[i].velocities[j];
385  }
386  if (!positions.empty())
387  {
388  positions[joint_state_idx_map[goal->trajectory.joint_names[j]]] = goal->trajectory.points[i].positions[j];
389  }
390  }
391 
392  // Converts the boundary conditions to splines.
393  for (size_t j = 0; j < joint_names_.size(); ++j)
394  {
395  if (prev_accelerations.size() > 0 && accelerations.size() > 0)
396  {
398  prev_positions[j], prev_velocities[j], prev_accelerations[j],
399  positions[j], velocities[j], accelerations[j],
400  durations[i],
401  seg.splines[j].coef);
402  }
403  else if (prev_velocities.size() > 0 && velocities.size() > 0)
404  {
406  prev_positions[j], prev_velocities[j],
407  positions[j], velocities[j],
408  durations[i],
409  seg.splines[j].coef);
410  seg.splines[j].coef.resize(6, 0.0);
411  }
412  else
413  {
414  seg.splines[j].coef[0] = prev_positions[j];
415  if (durations[i] == 0.0)
416  {
417  seg.splines[j].coef[1] = 0.0;
418  }
419  else
420  {
421  seg.splines[j].coef[1] = (positions[j] - prev_positions[j]) / durations[i];
422  }
423  seg.splines[j].coef[2] = 0.0;
424  seg.splines[j].coef[3] = 0.0;
425  seg.splines[j].coef[4] = 0.0;
426  seg.splines[j].coef[5] = 0.0;
427  }
428  }
429  // Pushes the splines onto the end of the new trajectory.
430 
431  traj.push_back(seg);
432 
433  // Computes the starting conditions for the next segment
434 
435  prev_positions = positions;
436  prev_velocities = velocities;
437  prev_accelerations = accelerations;
438  }
439 
440  // ------ Commits the new trajectory
441 
442  if (!new_traj_ptr)
443  {
444  ROS_ERROR("The new trajectory was null!");
445  return;
446  }
447 
448  ROS_DEBUG("The new trajectory has %d segments", static_cast<int>(traj.size()));
449 
450  std::vector<sr_robot_msgs::joint> joint_vector_traj;
451  unsigned int controller_pub_idx = 0;
452  // only one of these 2 will be used
453  std_msgs::Float64 target_msg;
454  sr_robot_msgs::sendupdate sendupdate_msg_traj;
455 
456  // initializes the joint names
457  // @todo check if traj only contains joint that we control
458  // joint_names_ = internal order. not goal->trajectory.joint_names;
459  joint_vector_traj.clear();
460 
461  for (unsigned int i = 0; i < joint_names_.size(); ++i)
462  {
463  sr_robot_msgs::joint joint;
464  joint.joint_name = joint_names_[i];
465  joint_vector_traj.push_back(joint);
466  }
467 
468  if (use_sendupdate)
469  {
470  sendupdate_msg_traj.sendupdate_length = joint_vector_traj.size();
471  ROS_DEBUG("Trajectory received: %d joints / %d msg length", static_cast<int>(goal->trajectory.joint_names.size()),
472  sendupdate_msg_traj.sendupdate_length);
473  }
474 
475  ros::Rate tmp_rate(1.0);
476 
477 // std::vector<trajectory_msgs::JointTrajectoryPoint> trajectory_points = goal->trajectory.points;
478 // trajectory_msgs::JointTrajectoryPoint trajectory_step;
479 
480  // loop through the steps
481  ros::Duration sleeping_time(0.0);
482  ROS_DEBUG("Entering the execution loop");
483 
485  while (ros::ok())
486  {
487  ros::Time time = ros::Time::now();
488  ros::Duration dt = time - last_time_;
489  last_time_ = time;
490 
491  // ------ Finds the current segment
492  ROS_DEBUG("Find current segment");
493 
494  // Determines which segment of the trajectory to use. (Not particularly realtime friendly).
495  int seg = -1;
496  while (seg + 1 < static_cast<int>(traj.size()) && traj[seg + 1].start_time < time.toSec())
497  {
498  ++seg;
499  }
500 
501  // if the last trajectory is already in the past, stop the servoing
502  if ((traj[traj.size() - 1].start_time + traj[traj.size() - 1].duration) < time.toSec())
503  {
504  ROS_DEBUG("trajectory is finished %f<%f", (traj[traj.size() - 1].start_time + traj[traj.size() - 1].duration),
505  time.toSec());
506  break;
507  }
508 
509  if (seg == -1)
510  {
511  if (traj.size() == 0)
512  ROS_ERROR("No segments in the trajectory");
513  else
514  ROS_ERROR("No earlier segments. First segment starts at %.3lf (now = %.3lf)", traj[0].start_time,
515  time.toSec());
516  success = false;
517  break;
518  }
519 
520  // ------ Trajectory Sampling
521  ROS_DEBUG("Sample the trajectory");
522 
523  for (size_t i = 0; i < q.size(); ++i)
524  {
525  sampleSplineWithTimeBounds(traj[seg].splines[i].coef, traj[seg].duration,
526  time.toSec() - traj[seg].start_time,
527  q[i], qd[i], qdd[i]);
528  }
529  ROS_DEBUG("Sampled the trajectory");
530  // check if preempted
531  if (action_server->isPreemptRequested() || !ros::ok())
532  {
533  ROS_INFO("Joint Trajectory Action Preempted");
534  // set the action state to preempted
535  action_server->setPreempted();
536  success = false;
537  break;
538  }
539  ROS_DEBUG("Update the targets");
540  // update the targets and publish target joint_states
541  sensor_msgs::JointState desired_joint_state_msg;
542  for (unsigned int i = 0; i < joint_names_.size(); ++i)
543  {
544  desired_joint_state_msg.name.push_back(joint_names_[i]);
545  desired_joint_state_msg.position.push_back(q[i]);
546  desired_joint_state_msg.velocity.push_back(qd[i]);
547  desired_joint_state_msg.effort.push_back(0.0);
548  if (!use_sendupdate)
549  {
550  if ((controller_pub_idx = jointPubIdxMap[joint_names_[i]]) > 0) // if a controller exist for this joint
551  {
552  target_msg.data = q[i];
553  controller_publishers.at(controller_pub_idx - 1).publish(target_msg);
554  }
555  }
556  else
557  {
558  joint_vector_traj[i].joint_target = q[i] * 57.3;
559  ROS_DEBUG("traj[%s]: %f", joint_vector_traj[i].joint_name.c_str(), joint_vector_traj[i].joint_target);
560  }
561  }
562  ROS_DEBUG("Targets updated");
563 
564  desired_joint_state_msg.header.stamp = ros::Time::now();
565  desired_joint_state_pusblisher.publish(desired_joint_state_msg);
566 
567  if (use_sendupdate)
568  {
569  sendupdate_msg_traj.sendupdate_list = joint_vector_traj;
570  sr_arm_target_pub.publish(sendupdate_msg_traj);
571  sr_hand_target_pub.publish(sendupdate_msg_traj);
572  }
573 
574  ROS_DEBUG("Now sleep and loop");
575  sleeping_time.sleep();
576  sleeping_time = ros::Duration(0.1);
577  ROS_DEBUG("redo loop");
578  }
579 
580  control_msgs::FollowJointTrajectoryResult joint_trajectory_result;
581 
582  if (success)
583  {
584  action_server->setSucceeded(joint_trajectory_result);
585  }
586  else
587  {
588  action_server->setAborted(joint_trajectory_result);
589  }
590  }
591 
593  const std::vector<double> &coefficients, double duration, double time,
594  double &position, double &velocity, double &acceleration)
595  {
596  if (time < 0)
597  {
598  double _;
599  sampleQuinticSpline(coefficients, 0.0, position, _, _);
600  velocity = 0;
601  acceleration = 0;
602  }
603  else if (time > duration)
604  {
605  double _;
606  sampleQuinticSpline(coefficients, duration, position, _, _);
607  velocity = 0;
608  acceleration = 0;
609  }
610  else
611  {
612  sampleQuinticSpline(coefficients, time,
613  position, velocity, acceleration);
614  }
615  }
616 
617  void JointTrajectoryActionController::commandCB(const trajectory_msgs::JointTrajectoryConstPtr &msg)
618  {
619  bool success = true;
620 
621  ros::Time time = ros::Time::now() - ros::Duration(0.05);
622  last_time_ = time;
623 
624  ROS_ERROR("Figuring out new trajectory at %.3lf, with data from %.3lf with %zu waypoints",
625  time.toSec(), msg->header.stamp.toSec(), msg->points.size());
626 
628  SpecifiedTrajectory &traj = *new_traj_ptr;
629 
630 
631  // Finds the end conditions of the final segment
632  std::vector<double> prev_positions(joint_names_.size());
633  std::vector<double> prev_velocities(joint_names_.size());
634  std::vector<double> prev_accelerations(joint_names_.size());
635 
637 
638  ROS_DEBUG("Initial conditions for new set of splines:");
639  for (size_t i = 0; i < joint_names_.size(); ++i)
640  {
641  double position;
642  if (getPosition(joint_names_[i], position))
643  {
644  prev_positions[i] = position;
645  }
646  else
647  {
648  ROS_ERROR("Cannot get joint_state, not executing trajectory");
649  return;
650  }
651  prev_velocities[i] = 0.0;
652  prev_accelerations[i] = 0.0;
653 
654  ROS_DEBUG(" %.2lf, %.2lf, %.2lf (%s)", prev_positions[i], prev_velocities[i],
655  prev_accelerations[i], joint_names_[i].c_str());
656  }
657  // ------ Tacks on the new segments
658  std::vector<double> positions;
659  std::vector<double> velocities;
660  std::vector<double> accelerations;
661 
662  std::vector<double> durations(msg->points.size());
663  if (msg->points.size() > 0)
664  {
665  durations[0] = msg->points[0].time_from_start.toSec();
666  }
667  for (size_t i = 1; i < msg->points.size(); ++i)
668  {
669  durations[i] = (msg->points[i].time_from_start - msg->points[i - 1].time_from_start).toSec();
670  }
671 
672  // no continuous joints so do not check if we should wrap
673 
674  // extract the traj
675  for (size_t i = 0; i < msg->points.size(); ++i)
676  {
677  Segment seg;
678  ROS_DEBUG("Current time %f and header time %f", msg->header.stamp.toSec(), ros::Time(0.0).toSec());
679  if (msg->header.stamp == ros::Time(0.0))
680  {
681  seg.start_time = (time + msg->points[i].time_from_start).toSec() - durations[i];
682  ROS_DEBUG("Segment %zu start time A %f,time_from_start %f, duration, %f", i, seg.start_time,
683  msg->points[i].time_from_start.toSec(), durations[i]);
684  }
685  else
686  {
687  seg.start_time = (msg->header.stamp + msg->points[i].time_from_start).toSec() - durations[i];
688  ROS_DEBUG("Segment start time B %f", seg.start_time);
689  }
690  seg.duration = durations[i];
691  seg.splines.resize(joint_names_.size());
692 
693  // Checks that the incoming segment has the right number of elements.
694  if (msg->points[i].accelerations.size() != 0 && msg->points[i].accelerations.size() != joint_names_.size())
695  {
696  ROS_DEBUG("Command point %d has %d elements for the accelerations", static_cast<int>(i),
697  static_cast<int>(msg->points[i].accelerations.size()));
698  return;
699  }
700  if (msg->points[i].velocities.size() != 0 && msg->points[i].velocities.size() != joint_names_.size())
701  {
702  ROS_DEBUG("Command point %d has %d elements for the velocities", static_cast<int>(i),
703  static_cast<int>(msg->points[i].velocities.size()));
704  return;
705  }
706  if (msg->points[i].positions.size() != joint_names_.size())
707  {
708  ROS_DEBUG("Command point %d has %d elements for the positions", static_cast<int>(i),
709  static_cast<int>(msg->points[i].positions.size()));
710  return;
711  }
712 
713  // Re-orders the joints in the command to match the internal joint order.
714  accelerations.resize(msg->points[i].accelerations.size());
715  velocities.resize(msg->points[i].velocities.size());
716  positions.resize(msg->points[i].positions.size());
717  for (size_t j = 0; j < joint_names_.size(); ++j)
718  {
719  if (!accelerations.empty())
720  {
721  accelerations[j] = msg->points[i].accelerations[j];
722  }
723  if (!velocities.empty())
724  {
725  velocities[j] = msg->points[i].velocities[j];
726  }
727  if (!positions.empty())
728  {
729  positions[j] = msg->points[i].positions[j];
730  }
731  }
732 
733  // Converts the boundary conditions to splines.
734  for (size_t j = 0; j < joint_names_.size(); ++j)
735  {
736  if (prev_accelerations.size() > 0 && accelerations.size() > 0)
737  {
739  prev_positions[j], prev_velocities[j], prev_accelerations[j],
740  positions[j], velocities[j], accelerations[j],
741  durations[i],
742  seg.splines[j].coef);
743  }
744  else if (prev_velocities.size() > 0 && velocities.size() > 0)
745  {
747  prev_positions[j], prev_velocities[j],
748  positions[j], velocities[j],
749  durations[i],
750  seg.splines[j].coef);
751  seg.splines[j].coef.resize(6, 0.0);
752  }
753  else
754  {
755  seg.splines[j].coef[0] = prev_positions[j];
756  if (durations[i] == 0.0)
757  {
758  seg.splines[j].coef[1] = 0.0;
759  }
760  else
761  {
762  seg.splines[j].coef[1] = (positions[j] - prev_positions[j]) / durations[i];
763  }
764  seg.splines[j].coef[2] = 0.0;
765  seg.splines[j].coef[3] = 0.0;
766  seg.splines[j].coef[4] = 0.0;
767  seg.splines[j].coef[5] = 0.0;
768  }
769  }
770  // Pushes the splines onto the end of the new trajectory.
771 
772  traj.push_back(seg);
773 
774  // Computes the starting conditions for the next segment
775 
776  prev_positions = positions;
777  prev_velocities = velocities;
778  prev_accelerations = accelerations;
779  }
780 
781  // ------ Commits the new trajectory
782 
783  if (!new_traj_ptr)
784  {
785  ROS_ERROR("The new trajectory was null!");
786  return;
787  }
788 
789  ROS_DEBUG("The new trajectory has %d segments", static_cast<int>(traj.size()));
790 
791  std::vector<sr_robot_msgs::joint> joint_vector_traj;
792  unsigned int controller_pub_idx = 0;
793  // only one of these 2 will be used
794  std_msgs::Float64 target_msg;
795  sr_robot_msgs::sendupdate sendupdate_msg_traj;
796 
797  // initializes the joint names
798  // @todo check if traj only contains joint that we control
799  // joint_names_ = goal->trajectory.joint_names;
800  joint_vector_traj.clear();
801 
802  for (unsigned int i = 0; i < joint_names_.size(); ++i)
803  {
804  sr_robot_msgs::joint joint;
805  joint.joint_name = joint_names_[i];
806  joint_vector_traj.push_back(joint);
807  }
808 
809  if (use_sendupdate)
810  {
811  sendupdate_msg_traj.sendupdate_length = joint_vector_traj.size();
812  ROS_DEBUG("Trajectory received: %d joints / %d msg length", static_cast<int>(msg->joint_names.size()),
813  sendupdate_msg_traj.sendupdate_length);
814  }
815 
816  ros::Rate tmp_rate(1.0);
817 
818  // loop through the steps
819  ros::Duration sleeping_time(0.0);
820  ROS_DEBUG("Entering the execution loop");
821 
822  while (ros::ok())
823  {
824  ros::Time time = ros::Time::now();
825  ros::Duration dt = time - last_time_;
826  last_time_ = time;
827 
828  // ------ Finds the current segment
829  ROS_DEBUG("Find current segment");
830 
831  // Determines which segment of the trajectory to use. (Not particularly realtime friendly).
832  int seg = -1;
833  while (seg + 1 < static_cast<int>(traj.size()) && traj[seg + 1].start_time < time.toSec())
834  {
835  ++seg;
836  }
837 
838  // if the last trajectory is already in the past, stop the servoing
839  if ((traj[traj.size() - 1].start_time + traj[traj.size() - 1].duration) < time.toSec())
840  {
841  ROS_DEBUG("trajectory is finished %f<%f", (traj[traj.size() - 1].start_time + traj[traj.size() - 1].duration),
842  time.toSec());
843  break;
844  }
845 
846  if (seg == -1)
847  {
848  if (traj.size() == 0)
849  ROS_ERROR("No segments in the trajectory");
850  else
851  ROS_ERROR("No earlier segments. First segment starts at %.3lf (now = %.3lf)", traj[0].start_time,
852  time.toSec());
853  return;
854  }
855 
856  // ------ Trajectory Sampling
857  ROS_DEBUG("Sample the trajectory");
858 
859  for (size_t i = 0; i < q.size(); ++i)
860  {
861  sampleSplineWithTimeBounds(traj[seg].splines[i].coef, traj[seg].duration,
862  time.toSec() - traj[seg].start_time,
863  q[i], qd[i], qdd[i]);
864  }
865  ROS_DEBUG("Sampled the trajectory");
866  // check if preempted
867  if (!ros::ok())
868  {
869  ROS_INFO("Joint Trajectory Stopping");
870  // set the action state to preempted
871  // action_server->setPreempted();
872  success = false;
873  break;
874  }
875  ROS_DEBUG("Update the targets");
876  // update the targets and publish target joint_states
877  sensor_msgs::JointState desired_joint_state_msg;
878  for (unsigned int i = 0; i < joint_names_.size(); ++i)
879  {
880  desired_joint_state_msg.name.push_back(joint_names_[i]);
881  desired_joint_state_msg.position.push_back(q[i]);
882  desired_joint_state_msg.velocity.push_back(qd[i]);
883  desired_joint_state_msg.effort.push_back(0.0);
884  if (!use_sendupdate)
885  {
886  if ((controller_pub_idx = jointPubIdxMap[joint_names_[i]]) > 0) // if a controller exist for this joint
887  {
888  target_msg.data = q[i];
889  controller_publishers.at(controller_pub_idx - 1).publish(target_msg);
890  }
891  }
892  else
893  {
894  joint_vector_traj[i].joint_target = q[i] * 57.3;
895  ROS_DEBUG("traj[%s]: %f", joint_vector_traj[i].joint_name.c_str(), joint_vector_traj[i].joint_target);
896  }
897  }
898  ROS_DEBUG("Targets updated");
899 
900  desired_joint_state_msg.header.stamp = ros::Time::now();
901  desired_joint_state_pusblisher.publish(desired_joint_state_msg);
902 
903  if (use_sendupdate)
904  {
905  sendupdate_msg_traj.sendupdate_list = joint_vector_traj;
906  sr_arm_target_pub.publish(sendupdate_msg_traj);
907  sr_hand_target_pub.publish(sendupdate_msg_traj);
908  }
909 
910  ROS_DEBUG("Now sleep and loop");
911  sleeping_time.sleep();
912  sleeping_time = ros::Duration(0.1);
913  ROS_DEBUG("redo loop");
914  }
915 
916  return;
917  }
918 } // namespace shadowrobot
919 
920 
921 int main(int argc, char **argv)
922 {
923  ros::init(argc, argv, "sr_joint_trajectory_action_controller");
924 
925  ros::AsyncSpinner spinner(1); // Use 1 thread
926  spinner.start();
928  ros::spin();
929  // ros::waitForShutdown();
930 
931  return 0;
932 }
933 
934 
935 /* For the emacs weenies in the crowd.
936 Local Variables:
937  c-basic-offset: 2
938 End:
939 */
940 
941 
942 
ServiceClient serviceClient(const std::string &service_name, bool persistent=false, const M_string &header_values=M_string())
void commandCB(const trajectory_msgs::JointTrajectoryConstPtr &msg)
static void sampleSplineWithTimeBounds(const std::vector< double > &coefficients, double duration, double time, double &position, double &velocity, double &acceleration)
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 sleep() const
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
bool call(MReq &req, MRes &res)
actionlib::SimpleActionServer< control_msgs::FollowJointTrajectoryAction > JTAS
#define ROS_WARN(...)
void spinner()
ROSCPP_DECL void spin(Spinner &spinner)
static void getQuinticSplineCoefficients(double start_pos, double start_vel, double start_acc, double end_pos, double end_vel, double end_acc, double time, std::vector< double > &coefficients)
#define ROS_INFO(...)
ROSCPP_DECL bool ok()
int main(int argc, char **argv)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
static void generatePowers(int n, double x, double *powers)
static void sampleQuinticSpline(const std::vector< double > &coefficients, double time, double &position, double &velocity, double &acceleration)
Samples a quintic spline segment at a particular time.
bool getParam(const std::string &key, std::string &s) const
static Time now()
ROSCPP_DECL void shutdown()
void execute_trajectory(const control_msgs::FollowJointTrajectoryGoalConstPtr &goal)
#define ROS_ERROR(...)
static void getCubicSplineCoefficients(double start_pos, double start_vel, double end_pos, double end_vel, double time, std::vector< double > &coefficients)
Implement an actionlib server to execute a control_msgs::JointTrajectoryAction. Follows the given tra...
ROSCPP_DECL bool waitForService(const std::string &service_name, int32_t timeout)
#define ROS_DEBUG(...)


sr_mechanism_controllers
Author(s): Ugo Cupcic
autogenerated on Tue Oct 13 2020 03:55:58