5050)
5151from trajectory_msgs .msg import (
5252 JointTrajectoryPoint ,
53+ JointTrajectory
5354)
5455
5556import 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