Skip to content

Commit 4f9e994

Browse files
committed
add subscriber for JointTrajectory as /command
1 parent aea70d9 commit 4f9e994

File tree

1 file changed

+115
-0
lines changed

1 file changed

+115
-0
lines changed

src/joint_trajectory_action/joint_trajectory_action.py

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
)
5151
from trajectory_msgs.msg import (
5252
JointTrajectoryPoint,
53+
JointTrajectory
5354
)
5455

5556
import baxter_control
@@ -68,6 +69,7 @@ def __init__(self, limb, reconfig_server, rate=100.0,
6869
FollowJointTrajectoryAction,
6970
execute_cb=self._on_trajectory_action,
7071
auto_start=False)
72+
self._command = rospy.Subscriber('robot/limb/' + limb + '/command', JointTrajectory, self._on_joint_trajectory)
7173
self._action_name = rospy.get_name()
7274
self._limb = baxter_interface.Limb(limb)
7375
self._enable = baxter_interface.RobotEnable()
@@ -488,3 +490,116 @@ def check_goal_state():
488490
self._result.error_code = self._result.GOAL_TOLERANCE_VIOLATED
489491
self._server.set_aborted(self._result)
490492
self._command_stop(goal.trajectory.joint_names, end_angles, start_time, dimensions_dict)
493+
494+
def _get_trajectory_parameters(self, joint_names):
495+
# For each input trajectory, if path, goal, or goal_time tolerances
496+
# provided, we will use these as opposed to reading from the
497+
# parameter server/dynamic reconfigure
498+
499+
# Goal time tolerance - time buffer allowing goal constraints to be met
500+
self._goal_time = self._dyn.config['goal_time']
501+
502+
# Stopped velocity tolerance - max velocity at end of execution
503+
self._stopped_velocity = self._dyn.config['stopped_velocity_tolerance']
504+
505+
# Path execution and goal tolerances per joint
506+
for jnt in joint_names:
507+
if not jnt in self._limb.joint_names():
508+
rospy.logerr(
509+
"%s: Trajectory Aborted - Provided Invalid Joint Name %s" %
510+
(self._action_name, jnt,))
511+
self._result.error_code = self._result.INVALID_JOINTS
512+
self._server.set_aborted(self._result)
513+
return
514+
# Path execution tolerance
515+
path_error = self._dyn.config[jnt + '_trajectory']
516+
self._path_thresh[jnt] = path_error
517+
518+
# Goal error tolerance
519+
goal_error = self._dyn.config[jnt + '_goal']
520+
self._goal_error[jnt] = goal_error
521+
522+
# PID gains if executing using the velocity (integral) controller
523+
if self._mode == 'velocity':
524+
self._pid[jnt].set_kp(self._dyn.config[jnt + '_kp'])
525+
self._pid[jnt].set_ki(self._dyn.config[jnt + '_ki'])
526+
self._pid[jnt].set_kd(self._dyn.config[jnt + '_kd'])
527+
self._pid[jnt].initialize()
528+
529+
def _on_joint_trajectory(self, trajectory):
530+
joint_names = trajectory.joint_names
531+
trajectory_points = trajectory.points
532+
533+
rospy.loginfo("%s: Executing requested joint trajectory" %
534+
(self._action_name,))
535+
536+
# Clear spline coefficients
537+
for jnt in xrange(len(joint_names)):
538+
self._coeff[jnt] = [0.0] * 6
539+
540+
# Load parameters for trajectory
541+
self._get_trajectory_parameters(joint_names)
542+
543+
# Create a new discretized joint trajectory
544+
num_points = len(trajectory_points)
545+
546+
if num_points == 0:
547+
rospy.logerr("%s: Empty Trajectory" % (self._command,))
548+
return
549+
550+
end_time = trajectory_points[-1].time_from_start.to_sec()
551+
control_rate = rospy.Rate(self._control_rate)
552+
553+
pnt_times = [pnt.time_from_start.to_sec() for pnt in trajectory_points]
554+
555+
#
556+
start_point = JointTrajectoryPoint()
557+
start_point.positions = self._get_current_position(joint_names)
558+
start_point.velocities = self._get_current_velocities(joint_names)
559+
start_point.accelerations = [0.0] * len(joint_names)
560+
561+
# Wait for the specified execution time, if not provided use now
562+
start_time = trajectory.header.stamp.to_sec()
563+
if start_time == 0.0:
564+
start_time = rospy.get_time()
565+
baxter_dataflow.wait_for(
566+
lambda: rospy.get_time() >= start_time,
567+
timeout=float('inf')
568+
)
569+
570+
# Loop until end of trajectory time. Provide a single time step
571+
# of the control rate past the end to ensure we get to the end.
572+
now_from_start = rospy.get_time() - start_time
573+
# Keep track of current indices for spline segment generation
574+
last_idx = -1
575+
while (now_from_start < end_time and not rospy.is_shutdown()):
576+
idx = bisect.bisect(pnt_times, now_from_start)
577+
578+
if idx == 0:
579+
# If our current time is before the first specified point
580+
# in the trajectory, then we should interpolate between
581+
# our start position and that point.
582+
p1 = deepcopy(start_point)
583+
else:
584+
p1 = deepcopy(trajectory_points[idx - 1])
585+
586+
if idx != num_points:
587+
p2 = trajectory_points[idx]
588+
# If entering a new trajectory segment, calculate coefficients
589+
if last_idx != idx:
590+
self._compute_spline_coefficients(p1, p2)
591+
# Find goal command point at commanded time
592+
cmd_time = now_from_start - p1.time_from_start.to_sec()
593+
point = self._get_point(joint_names, cmd_time)
594+
else:
595+
# If the current time is after the last trajectory point,
596+
# just hold that position.
597+
point = p1
598+
599+
if not self._command_joints(joint_names, point):
600+
return
601+
602+
control_rate.sleep()
603+
now_from_start = rospy.get_time() - start_time
604+
last_idx = idx
605+

0 commit comments

Comments
 (0)