Newer
Older
import roslib; roslib.load_manifest('ur5_driver')
Stuart Glaser
committed
import copy
import traceback, code
import actionlib
from sensor_msgs.msg import JointState
from control_msgs.msg import FollowJointTrajectoryAction
Stuart Glaser
committed
from trajectory_msgs.msg import JointTrajectory, JointTrajectoryPoint
Stuart Glaser
committed
from deserialize import RobotState, RobotMode
Stuart Glaser
committed
prevent_programming = False
Stuart Glaser
committed
PORT=30002
REVERSE_PORT = 50001
MSG_OUT = 1
MSG_QUIT = 2
MSG_JOINT_STATES = 3
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]
connected_robot = None
connected_robot_lock = threading.Lock()
connected_robot_cond = threading.Condition(connected_robot_lock)
pub_joint_states = rospy.Publisher('joint_states', JointState)
Stuart Glaser
committed
#dump_state = open('dump_state', 'wb')
def dumpstacks():
id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
code = []
for threadId, stack in sys._current_frames().items():
code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""), threadId))
for filename, lineno, name, line in traceback.extract_stack(stack):
code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
if line:
code.append(" %s" % (line.strip()))
print "\n".join(code)
def log(s):
print "[%s] %s" % (datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f'), s)
Stuart Glaser
committed
class UR5Connection(object):
TIMEOUT = 1.0
DISCONNECTED = 0
CONNECTED = 1
READY_TO_PROGRAM = 2
EXECUTING = 3
def __init__(self, hostname, port, program):
self.__thread = None
self.__sock = None
self.robot_state = self.DISCONNECTED
self.hostname = hostname
self.port = port
self.program = program
self.last_state = None
def connect(self):
if self.__sock:
self.disconnect()
self.__buf = ""
self.robot_state = self.CONNECTED
self.__sock = socket.create_connection((self.hostname, self.port))
self.__keep_running = True
self.__thread = threading.Thread(name="UR5Connection", target=self.__run)
self.__thread.daemon = True
self.__thread.start()
def send_program(self):
Stuart Glaser
committed
global prevent_programming
if prevent_programming:
rospy.loginfo("Programming is currently prevented")
return
assert self.robot_state in [self.READY_TO_PROGRAM, self.EXECUTING]
Stuart Glaser
committed
rospy.loginfo("Programming the robot at %s" % self.hostname)
self.__sock.sendall(self.program)
self.robot_state = self.EXECUTING
def disconnect(self):
if self.__thread:
self.__keep_running = False
self.__thread.join()
self.__thread = None
if self.__sock:
self.__sock.close()
self.__sock = None
self.last_state = None
self.robot_state = self.DISCONNECTED
def ready_to_program(self):
return self.robot_state in [self.READY_TO_PROGRAM, self.EXECUTING]
Stuart Glaser
committed
def __trigger_disconnected(self):
log("Robot disconnected")
self.robot_state = self.DISCONNECTED
def __trigger_ready_to_program(self):
rospy.loginfo("Robot ready to program")
def __trigger_halted(self):
log("Halted")
def __on_packet(self, buf):
state = RobotState.unpack(buf)
self.last_state = state
#import deserialize; deserialize.pstate(self.last_state)
#log("Packet. Mode=%s" % state.robot_mode_data.robot_mode)
# If the urscript program is not executing, then the driver
# needs to publish joint states using information from the
# robot state packet.
if self.robot_state != self.EXECUTING:
msg = JointState()
msg.header.stamp = rospy.get_rostime()
msg.header.frame_id = "From binary state data"
msg.name = JOINT_NAMES
msg.position = [jd.q_actual for jd in state.joint_data]
msg.velocity = [jd.qd_actual for jd in state.joint_data]
msg.effort = [0]*6
pub_joint_states.publish(msg)
self.last_joint_states = msg
# Updates the state machine that determines whether we can program the robot.
Stuart Glaser
committed
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
can_execute = (state.robot_mode_data.robot_mode in [RobotMode.READY, RobotMode.RUNNING])
if self.robot_state == self.CONNECTED:
if can_execute:
self.__trigger_ready_to_program()
self.robot_state = self.READY_TO_PROGRAM
elif self.robot_state == self.READY_TO_PROGRAM:
if not can_execute:
self.robot_state = self.CONNECTED
elif self.robot_state == self.EXECUTING:
if not can_execute:
self.__trigger_halted()
self.robot_state = self.CONNECTED
def __run(self):
while self.__keep_running:
r, _, _ = select.select([self.__sock], [], [], self.TIMEOUT)
if r:
more = self.__sock.recv(4096)
if more:
self.__buf = self.__buf + more
# Attempts to extract a packet
packet_length, ptype = struct.unpack_from("!IB", self.__buf)
if packet_length >= len(self.__buf):
packet, self.__buf = self.__buf[:packet_length], self.__buf[packet_length:]
self.__on_packet(packet)
else:
self.__trigger_disconnected()
self.__keep_running = False
else:
self.__trigger_disconnected()
self.__keep_running = False
def setConnectedRobot(r):
global connected_robot, connected_robot_lock
with connected_robot_lock:
connected_robot = r
connected_robot_cond.notify()
def getConnectedRobot(wait=False, timeout=-1):
started = time.time()
with connected_robot_lock:
if wait:
while not connected_robot:
if timeout >= 0 and time.time() > started + timeout:
break
connected_robot_cond.wait(0.2)
return connected_robot
Stuart Glaser
committed
# Receives messages from the robot over the socket
class CommanderTCPHandler(SocketServer.BaseRequestHandler):
while True:
r, _, _ = select.select([self.request], [], [], 0.2)
if r:
more = self.request.recv(4096)
if not more:
raise EOF()
return more
else:
if self.last_joint_states and \
self.last_joint_states.header.stamp.to_sec() < time.time() + 1.0:
rospy.logerr("Stopped hearing from robot. Disconnected")
raise EOF()
self.socket_lock = threading.Lock()
setConnectedRobot(self)
print "Handling a request"
try:
buf = self.recv_more()
if not buf: return
while True:
Stuart Glaser
committed
#print "Buf:", [ord(b) for b in buf]
# Unpacks the message type
mtype = struct.unpack_from("!i", buf, 0)[0]
buf = buf[4:]
Stuart Glaser
committed
#print "Message type:", mtype
if mtype == MSG_OUT:
# Unpacks string message, terminated by tilde
i = buf.find("~")
while i < 0:
buf = buf + self.recv_more()
i = buf.find("~")
if len(buf) > 2000:
raise Exception("Probably forgot to terminate a string: %s..." % buf[:150])
s, buf = buf[:i], buf[i+1:]
elif mtype == MSG_JOINT_STATES:
while len(buf) < 3*(6*4):
buf = buf + self.recv_more()
state_mult = struct.unpack_from("!%ii" % (3*6), buf, 0)
buf = buf[3*6*4:]
state = [s / MULT_jointstate for s in state_mult]
msg = JointState()
msg.header.stamp = rospy.get_rostime()
msg.name = JOINT_NAMES
msg.position = state[:6]
msg.velocity = state[6:12]
msg.effort = state[12:18]
pub_joint_states.publish(msg)
elif mtype == MSG_QUIT:
print "Quitting"
elif mtype == MSG_WAYPOINT_FINISHED:
while len(buf) < 4:
buf = buf + self.recv_more()
waypoint_id = struct.unpack_from("!i", buf, 0)[0]
buf = buf[4:]
print "Waypoint finished (not handled)"
else:
raise Exception("Unknown message type: %i" % mtype)
if not buf:
buf = buf + self.recv_more()
except EOF:
Stuart Glaser
committed
print "Connection closed (command)"
setConnectedRobot(None)
def send_quit(self):
with self.socket_lock:
self.request.send(struct.pack("!i", MSG_QUIT))
def send_movej(self, waypoint_id, q, a=3, v=0.75, t=0, r=0):
params = [MSG_MOVEJ, waypoint_id] + \
[MULT_jointstate * qq for qq in q] + \
[MULT_jointstate * a, MULT_jointstate * v, MULT_time * t, MULT_blend * r]
buf = struct.pack("!%ii" % len(params), *params)
with self.socket_lock:
self.request.send(buf)
def send_servoj(self, waypoint_id, q, t):
assert(len(q) == 6)
params = [MSG_SERVOJ, waypoint_id] + \
[MULT_jointstate * qq for qq in q] + \
[MULT_time * t]
buf = struct.pack("!%ii" % len(params), *params)
with self.socket_lock:
self.request.send(buf)
def send_stopj(self):
with self.socket_lock:
self.request.send(struct.pack("!i", MSG_STOPJ))
def set_waypoint_finished_cb(self, cb):
self.waypoint_finished_cb = cb
Stuart Glaser
committed
# Returns the last JointState message sent out
def get_joint_states(self):
return self.last_joint_states
class TCPServer(SocketServer.TCPServer):
allow_reuse_address = True # Allows the program to restart gracefully on crash
Stuart Glaser
committed
# Waits until all threads have completed. Allows KeyboardInterrupt to occur
def joinAll(threads):
while any(t.isAlive() for t in threads):
for t in threads:
Stuart Glaser
committed
# 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()
# Reorders the JointTrajectory traj according to the order in
# joint_names. Destructive.
def reorder_traj_joints(traj, joint_names):
order = [traj.joint_names.index(j) for j in joint_names]
new_points = []
for p in traj.points:
new_points.append(JointTrajectoryPoint(
positions = [p.positions[i] for i in order],
velocities = [p.velocities[i] for i in order] if p.velocities else [],
accelerations = [p.accelerations[i] for i in order] if p.accelerations else [],
time_from_start = p.time_from_start))
traj.joint_names = joint_names
traj.points = new_points
Stuart Glaser
committed
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
def interp_cubic(p0, p1, t_abs):
T = (p1.time_from_start - p0.time_from_start).to_sec()
t = t_abs - p0.time_from_start.to_sec()
q = [0] * 6
qdot = [0] * 6
qddot = [0] * 6
for i in range(len(p0.positions)):
a = p0.positions[i]
b = p0.velocities[i]
c = (-3*p0.positions[i] + 3*p1.positions[i] - 2*T*p0.velocities[i] - T*p1.velocities[i]) / T**2
d = (2*p0.positions[i] - 2*p1.positions[i] + T*p0.velocities[i] + T*p1.velocities[i]) / T**3
q[i] = a + b*t + c*t**2 + d*t**3
qdot[i] = b + 2*c*t + 3*d*t**2
qddot[i] = 2*c + 6*d*t
return JointTrajectoryPoint(q, qdot, qddot, rospy.Duration(t_abs))
# Returns (q, qdot, qddot) for sampling the JointTrajectory at time t.
# The time t is the time since the trajectory was started.
def sample_traj(traj, t):
# First point
if t <= 0.0:
return copy.deepcopy(traj.points[0])
# Last point
if t >= traj.points[-1].time_from_start.to_sec():
return copy.deepcopy(traj.points[-1])
# Finds the (middle) segment containing t
i = 0
while traj.points[i+1].time_from_start.to_sec() < t:
i += 1
return interp_cubic(traj.points[i], traj.points[i+1], t)
class UR5TrajectoryFollower(object):
Stuart Glaser
committed
RATE = 0.02
def __init__(self, robot):
self.following_lock = threading.Lock()
self.T0 = time.time()
self.robot = robot
self.server = actionlib.ActionServer("follow_joint_trajectory",
FollowJointTrajectoryAction,
self.on_goal, self.on_cancel, auto_start=False)
self.goal_handle = None
Stuart Glaser
committed
self.traj = None
self.traj_t0 = 0.0
self.first_waypoint_id = 10
self.tracking_i = 0
self.pending_i = 0
self.update_timer = rospy.Timer(rospy.Duration(self.RATE), self._update)
def set_robot(self, robot):
# Cancels any goals in progress
if self.goal_handle:
self.goal_handle.set_canceled()
self.goal_handle = None
self.traj = None
self.robot = robot
if self.robot:
self.init_traj_from_robot()
# Sets the trajectory to remain stationary at the current position
# of the robot.
Stuart Glaser
committed
def init_traj_from_robot(self):
if not self.robot: raise Exception("No robot connected")
Stuart Glaser
committed
# Busy wait (avoids another mutex)
state = self.robot.get_joint_states()
while not state:
time.sleep(0.1)
state = self.robot.get_joint_states()
self.traj_t0 = time.time()
self.traj = JointTrajectory()
self.traj.joint_names = JOINT_NAMES
self.traj.points = [JointTrajectoryPoint(
positions = state.position,
velocities = [0] * 6,
accelerations = [0] * 6,
time_from_start = rospy.Duration(0.0))]
def start(self):
Stuart Glaser
committed
self.init_traj_from_robot()
self.server.start()
def on_goal(self, goal_handle):
log("on_goal")
# Checks that the robot is connected
if not self.robot:
rospy.logerr("Received a goal, but the robot is not connected")
goal_handle.set_rejected()
return
# Checks if the joints are just incorrect
if set(goal_handle.get_goal().trajectory.joint_names) != set(JOINT_NAMES):
rospy.logerr("Received a goal with incorrect joint names: (%s)" % \
', '.join(goal_handle.get_goal().trajectory.joint_names))
goal_handle.set_rejected()
return
# Orders the joints of the trajectory according to JOINT_NAMES
reorder_traj_joints(goal_handle.get_goal().trajectory, JOINT_NAMES)
with self.following_lock:
if self.goal_handle:
# Cancels the existing goal
self.goal_handle.set_canceled()
self.first_waypoint_id += len(self.goal_handle.get_goal().trajectory.points)
self.goal_handle = None
Stuart Glaser
committed
# Inserts the current setpoint at the head of the trajectory
now = time.time()
point0 = sample_traj(self.traj, now)
point0.time_from_start = rospy.Duration(0.0)
goal_handle.get_goal().trajectory.points.insert(0, point0)
self.traj_t0 = now
Stuart Glaser
committed
# Replaces the goal
self.goal_handle = goal_handle
self.traj = goal_handle.get_goal().trajectory
self.goal_handle.set_accepted()
Stuart Glaser
committed
log("on_cancel")
if goal_handle == self.goal_handle:
with self.following_lock:
# Uses the next little bit of trajectory to slow to a stop
Stuart Glaser
committed
STOP_DURATION = 0.5
now = time.time()
point0 = sample_traj(self.traj, now - self.traj_t0)
point0.time_from_start = rospy.Duration(0.0)
point1 = sample_traj(self.traj, now - self.traj_t0 + STOP_DURATION)
point1.velocities = [0] * 6
point1.accelerations = [0] * 6
point1.time_from_start = rospy.Duration(STOP_DURATION)
self.traj_t0 = now
self.traj = JointTrajectory()
self.traj.joint_names = JOINT_NAMES
self.traj.points = [point0, point1]
self.goal_handle.set_canceled()
self.goal_handle = None
else:
goal_handle.set_canceled()
if self.robot and self.traj:
Stuart Glaser
committed
now = time.time()
if (now - self.traj_t0) <= self.traj.points[-1].time_from_start.to_sec():
setpoint = sample_traj(self.traj, now - self.traj_t0)
try:
self.robot.send_servoj(999, setpoint.positions, 2 * self.RATE)
except socket.error:
pass
Stuart Glaser
committed
else: # Off the end
if self.goal_handle:
self.goal_handle.set_succeeded()
self.goal_handle = None
rospy.init_node('ur5_driver', disable_signals=True)
if rospy.get_param("use_sim_time", False):
rospy.logfatal("use_sim_time is set!!!")
sys.exit(1)
Stuart Glaser
committed
global prevent_programming
prevent_programming = rospy.get_param("prevent_programming", False)
# Parses command line arguments
parser = optparse.OptionParser(usage="usage: %prog robot_hostname")
(options, args) = parser.parse_args(rospy.myargv()[1:])
if len(args) != 1:
parser.error("You must specify the robot hostname")
robot_hostname = args[0]
# Sets up the server for the robot to connect to
server = TCPServer(("", 50001), CommanderTCPHandler)
thread_commander = threading.Thread(name="CommanderHandler", target=server.serve_forever)
thread_commander.daemon = True
thread_commander.start()
Stuart Glaser
committed
Eitan Marder-Eppstein
committed
with open(roslib.packages.get_pkg_dir('ur5_driver') + '/prog') as fin:
Stuart Glaser
committed
program = fin.read() % {"driver_hostname": socket.getfqdn()}
connection = UR5Connection(robot_hostname, PORT, program)
connection.connect()
action_server = None
while True:
# Checks for disconnect
if getConnectedRobot(wait=False):
time.sleep(0.2)
else:
print "Disconnected. Reconnecting"
if action_server:
action_server.set_robot(None)
rospy.loginfo("Programming the robot")
while True:
Stuart Glaser
committed
# Sends the program to the robot
while not connection.ready_to_program():
print "Waiting to program"
time.sleep(1.0)
connection.send_program()
r = getConnectedRobot(wait=True, timeout=1.0)
if r:
break
rospy.loginfo("Robot connected")
if action_server:
action_server.set_robot(r)
else:
action_server = UR5TrajectoryFollower(r)
action_server.start()
except KeyboardInterrupt:
try:
rospy.signal_shutdown("KeyboardInterrupt")
if r: r.send_quit()
except:
pass
if __name__ == '__main__': main()