From a0b1c2c9abfea349cb049e0efb20f542ee10f45d Mon Sep 17 00:00:00 2001 From: Stuart Glaser <sglaser@willowgarage.com> Date: Tue, 27 Mar 2012 15:51:08 -0700 Subject: [PATCH] Following trajectories sent to the action server. Still brittle --- ur5_driver/driver.py | 127 ++++++++++++++++++++++++++++++++++++---- ur5_driver/manifest.xml | 2 + ur5_driver/prog | 10 ++-- ur5_driver/test.launch | 6 ++ ur5_driver/test_move.py | 37 ++++++++++++ 5 files changed, 164 insertions(+), 18 deletions(-) create mode 100644 ur5_driver/test.launch create mode 100755 ur5_driver/test_move.py diff --git a/ur5_driver/driver.py b/ur5_driver/driver.py index c82e32c..48de91f 100755 --- a/ur5_driver/driver.py +++ b/ur5_driver/driver.py @@ -5,8 +5,11 @@ import datetime import socket import struct import SocketServer + import rospy +import actionlib from sensor_msgs.msg import JointState +from control_msgs.msg import FollowJointTrajectoryAction HOSTNAME='ur-xx' HOSTNAME="10.0.1.20" @@ -60,9 +63,10 @@ class CommanderTCPHandler(SocketServer.BaseRequestHandler): if not more: raise EOF() return more - + def handle(self): self.socket_lock = threading.Lock() + self.waypoint_finished_cb = None setConnectedRobot(self) #print "Handling a request" try: @@ -110,7 +114,8 @@ class CommanderTCPHandler(SocketServer.BaseRequestHandler): buf = buf + self.recv_more() waypoint_id = struct.unpack_from("!i", buf, 0)[0] buf = buf[4:] - log("Waypoint finished: %i" % waypoint_id) + if self.waypoint_finished_cb: + self.waypoint_finished_cb(waypoint_id) else: raise Exception("Unknown message type: %i" % mtype) @@ -132,6 +137,10 @@ class CommanderTCPHandler(SocketServer.BaseRequestHandler): with self.socket_lock: self.request.send(buf) + def set_waypoint_finished_cb(self, cb): + self.waypoint_finished_cb = cb + + class TCPServer(SocketServer.TCPServer): allow_reuse_address = True # Allows the program to restart gracefully on crash timeout = 5 @@ -143,6 +152,92 @@ def joinAll(threads): for t in threads: t.join(0.2) +# Returns the duration between moving from point (index-1) to point +# index in the given JointTrajectory +def get_segment_duration(traj, index): + if index == 0: + return traj.points[0].time_from_start.to_sec() + return (traj.points[index].time_from_start - traj.points[index-1].time_from_start).to_sec() + +class UR5TrajectoryFollower(object): + def __init__(self, robot): + self.robot = robot + self.server = actionlib.ActionServer("follow_joint_trajectory", + FollowJointTrajectoryAction, + self.on_goal, self.on_cancel, auto_start=False) + self.robot.set_waypoint_finished_cb(self.on_waypoint_finished) + + self.goal_handle = None + self.first_waypoint_id = 10 + self.tracking_i = 0 + self.pending_i = 0 + self.goal_start_time = rospy.Time(0) + + self.following_lock = threading.Lock() + + def start(self): + self.server.start() + + def on_goal(self, goal_handle): + log("on_goal") + if self.goal_handle: + rospy.logerr("Already have a goal in progress! Rejecting. (TODO)") + goal_handle.set_rejected() + return + + # TODO: Verify that the goal has the correct joints. Reorder if necessary + + with self.following_lock: + self.goal_handle = goal_handle + self.tracking_i = 0 + self.pending_i = 0 + self.goal_start_time = rospy.get_rostime() + + # Sends a tracking point and a pending point to the robot + self.goal_handle.set_accepted() + traj = self.goal_handle.get_goal().trajectory + # TODO: joints may have a different order + self.robot.send_movej(self.first_waypoint_id, traj.points[0].positions, + t=get_segment_duration(traj, 0)) + self.robot.send_movej(self.first_waypoint_id + 1, traj.points[1].positions, + t=get_segment_duration(traj, 1)) + self.tracking_i = 0 + self.pending_i = 1 + + def on_cancel(self): + log("on_cancel") + print "TODO: on_cancel" + + # The URScript program sends back waypoint_finished messages, + # which trigger this callback. + def on_waypoint_finished(self, waypoint_id): + log("Waypoint finished: %i" % waypoint_id) + index = waypoint_id - self.first_waypoint_id + if index != self.tracking_i: + rospy.logerr("Completed waypoint %i (id=%i), but tracking %i (id=%i)" % \ + (index, waypoint_id, self.tracking_i, + self.first_waypoint_id + self.tracking_i)) + # TODO: Probably need to fail here + + traj = self.goal_handle.get_goal().trajectory + traj_len = len(traj.points) + + # Checks if we've completed the trajectory + if index == traj_len - 1: + self.goal_handle.set_succeeded() + self.first_waypoint_id += traj_len + self.goal_handle = None + + # Moves onto the next segment + self.tracking_i += 1 + if self.pending_i + 1 < traj_len: + self.pending_i += 1 + # TODO: reorder joint positions + self.robot.send_movej(self.first_waypoint_id + self.pending_i, + traj.points[self.pending_i], + t=get_segment_duration(traj, self.pending_i)) + + sock = None def main(): global sock @@ -162,17 +257,25 @@ def main(): r = getConnectedRobot(wait=True) print "Robot connected" - log("movej Q1") - r.send_movej(1, Q1, t=2.0) - log("movej Q2") - r.send_movej(2, Q2, t=1.0) - time.sleep(3) - - print "Sending quit" - r.send_quit() + action_server = UR5TrajectoryFollower(r) + action_server.start() + + try: + + #log("movej Q1") + #r.send_movej(1, Q1, t=2.0) + #log("movej Q2") + #r.send_movej(2, Q2, t=1.0) + #time.sleep(3) + + #r.send_quit() - # Waits for the threads to finish - joinAll([thread_commander]) + # Waits for the threads to finish + joinAll([thread_commander]) + except KeyboardInterrupt: + r.send_quit() + rospy.signal_shutdown("KeyboardInterrupt") + raise ''' print "Dump" diff --git a/ur5_driver/manifest.xml b/ur5_driver/manifest.xml index 4917f4b..6cedb0d 100644 --- a/ur5_driver/manifest.xml +++ b/ur5_driver/manifest.xml @@ -10,6 +10,8 @@ <url>http://ros.org/wiki/ur5_driver</url> <depend package="rospy" /> + <depend package="actionlib" /> + <depend package="control_msgs" /> </package> diff --git a/ur5_driver/prog b/ur5_driver/prog index 9f5cff9..30280d0 100644 --- a/ur5_driver/prog +++ b/ur5_driver/prog @@ -5,7 +5,7 @@ def driverProg(): MSG_JOINT_STATES = 3 MSG_MOVEJ = 4 MSG_WAYPOINT_FINISHED = 5 - MULT_jointstate = 1000 + MULT_jointstate = 1000.0 MULT_time = 1000000.0 MULT_blend = 1000.0 @@ -70,13 +70,12 @@ def driverProg(): #movej([2.2,0,-1.57,0,0,0],2) #movej([1.5,0,-1.57,0,0,0],2) - i = 0 - while i < 100: - send_out("Listening") + while True: + #send_out("Listening") ll = socket_read_binary_integer(1) if ll[0] == 0: - send_out("Received nothing") + #send_out("Received nothing") elif ll[0] > 1: send_out("Received too many things") else: @@ -115,7 +114,6 @@ def driverProg(): end #movej([2.2,0,-1.57,0,0,0],2) #movej([1.5,0,-1.57,0,0,0],2) - i = i + 1 end #sleep(1) diff --git a/ur5_driver/test.launch b/ur5_driver/test.launch new file mode 100644 index 0000000..b49ed2b --- /dev/null +++ b/ur5_driver/test.launch @@ -0,0 +1,6 @@ +<launch> + <include file="$(find ur5_description)/launch/load.launch" /> + <node name="robot_state_publisher" pkg="robot_state_publisher" type="state_publisher" /> + <node name="rviz" pkg="rviz" type="rviz" args="-d $(find urdf_tutorial)/urdf.vcg" /> + +</launch> diff --git a/ur5_driver/test_move.py b/ur5_driver/test_move.py new file mode 100755 index 0000000..4812d7a --- /dev/null +++ b/ur5_driver/test_move.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +import roslib; roslib.load_manifest('ur5_driver') +import rospy +import actionlib +from control_msgs.msg import * +from trajectory_msgs.msg import * + +JOINT_NAMES = ['shoulder_pan_joint', 'shoulder_lift_joint', 'elbow_joint', + 'wrist_1_joint', 'wrist_2_joint', 'wrist_3_joint'] +Q1 = [2.2,0,-1.57,0,0,0] +Q2 = [1.5,0,-1.57,0,0,0] + +client = None + +def move1(): + g = FollowJointTrajectoryGoal() + g.trajectory = JointTrajectory() + g.trajectory.joint_names = JOINT_NAMES + g.trajectory.points = [ + JointTrajectoryPoint(positions=Q1, velocities=[0]*6, time_from_start=rospy.Duration(2.0)), + JointTrajectoryPoint(positions=Q2, velocities=[0]*6, time_from_start=rospy.Duration(3.0))] + client.send_goal(g) + +def main(): + global client + try: + rospy.init_node("test_move", anonymous=True, disable_signals=True) + client = actionlib.SimpleActionClient('follow_joint_trajectory', FollowJointTrajectoryAction) + print "Waiting for server..." + client.wait_for_server() + print "Connected to server" + move1() + except KeyboardInterrupt: + rospy.signal_shutdown("KeyboardInterrupt") + raise + +if __name__ == '__main__': main() -- GitLab