00001
00002 import roslib; roslib.load_manifest('ur_driver')
00003 import time, sys, threading, math
00004 import copy
00005 import datetime
00006 import socket, select
00007 import struct
00008 import traceback, code
00009 import optparse
00010 import SocketServer
00011
00012 import rospy
00013 import actionlib
00014 from sensor_msgs.msg import JointState
00015 from control_msgs.msg import FollowJointTrajectoryAction
00016 from trajectory_msgs.msg import JointTrajectory, JointTrajectoryPoint
00017 from geometry_msgs.msg import WrenchStamped
00018
00019 from dynamic_reconfigure.server import Server
00020 from ur_driver.cfg import URDriverConfig
00021
00022 from ur_driver.deserialize import RobotState, RobotMode
00023 from ur_driver.deserializeRT import RobotStateRT
00024
00025 from ur_msgs.srv import SetPayload, SetIO
00026 from ur_msgs.msg import *
00027
00028
00029 DigitalIn = Digital
00030 DigitalOut = Digital
00031 Flag = Digital
00032
00033 prevent_programming = False
00034
00035
00036
00037
00038
00039
00040 joint_offsets = {}
00041
00042 PORT=30002
00043 RT_PORT=30003
00044 DEFAULT_REVERSE_PORT = 50001
00045
00046 MSG_OUT = 1
00047 MSG_QUIT = 2
00048 MSG_JOINT_STATES = 3
00049 MSG_MOVEJ = 4
00050 MSG_WAYPOINT_FINISHED = 5
00051 MSG_STOPJ = 6
00052 MSG_SERVOJ = 7
00053 MSG_SET_PAYLOAD = 8
00054 MSG_WRENCH = 9
00055 MSG_SET_DIGITAL_OUT = 10
00056 MSG_GET_IO = 11
00057 MSG_SET_FLAG = 12
00058 MSG_SET_TOOL_VOLTAGE = 13
00059 MSG_SET_ANALOG_OUT = 14
00060 MULT_payload = 1000.0
00061 MULT_wrench = 10000.0
00062 MULT_jointstate = 10000.0
00063 MULT_time = 1000000.0
00064 MULT_blend = 1000.0
00065 MULT_analog = 1000000.0
00066 MULT_analog_robotstate = 0.1
00067
00068
00069 MAX_VELOCITY = 10.0
00070
00071
00072
00073 MIN_PAYLOAD = 0.0
00074 MAX_PAYLOAD = 1.0
00075
00076
00077
00078 IO_SLEEP_TIME = 0.05
00079
00080 JOINT_NAMES = ['shoulder_pan_joint', 'shoulder_lift_joint', 'elbow_joint',
00081 'wrist_1_joint', 'wrist_2_joint', 'wrist_3_joint']
00082
00083 Q1 = [2.2,0,-1.57,0,0,0]
00084 Q2 = [1.5,0,-1.57,0,0,0]
00085 Q3 = [1.5,-0.2,-1.57,0,0,0]
00086
00087
00088 connected_robot = None
00089 connected_robot_lock = threading.Lock()
00090 connected_robot_cond = threading.Condition(connected_robot_lock)
00091 last_joint_states = None
00092 last_joint_states_lock = threading.Lock()
00093 pub_joint_states = rospy.Publisher('joint_states', JointState, queue_size=1)
00094 pub_wrench = rospy.Publisher('wrench', WrenchStamped, queue_size=1)
00095 pub_io_states = rospy.Publisher('io_states', IOStates, queue_size=1)
00096
00097
00098 class EOF(Exception): pass
00099
00100 def dumpstacks():
00101 id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
00102 code = []
00103 for threadId, stack in sys._current_frames().items():
00104 code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""), threadId))
00105 for filename, lineno, name, line in traceback.extract_stack(stack):
00106 code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
00107 if line:
00108 code.append(" %s" % (line.strip()))
00109 print "\n".join(code)
00110
00111 def log(s):
00112 print "[%s] %s" % (datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f'), s)
00113
00114
00115 RESET_PROGRAM = '''def resetProg():
00116 sleep(0.0)
00117 end
00118 '''
00119
00120
00121 class URConnection(object):
00122 TIMEOUT = 1.0
00123
00124 DISCONNECTED = 0
00125 CONNECTED = 1
00126 READY_TO_PROGRAM = 2
00127 EXECUTING = 3
00128
00129 def __init__(self, hostname, port, program):
00130 self.__thread = None
00131 self.__sock = None
00132 self.robot_state = self.DISCONNECTED
00133 self.hostname = hostname
00134 self.port = port
00135 self.program = program
00136 self.last_state = None
00137
00138 def connect(self):
00139 if self.__sock:
00140 self.disconnect()
00141 self.__buf = ""
00142 self.robot_state = self.CONNECTED
00143 self.__sock = socket.create_connection((self.hostname, self.port))
00144 self.__keep_running = True
00145 self.__thread = threading.Thread(name="URConnection", target=self.__run)
00146 self.__thread.daemon = True
00147 self.__thread.start()
00148
00149 def send_program(self):
00150 global prevent_programming
00151 if prevent_programming:
00152 rospy.loginfo("Programming is currently prevented")
00153 return
00154 assert self.robot_state in [self.READY_TO_PROGRAM, self.EXECUTING]
00155 rospy.loginfo("Programming the robot at %s" % self.hostname)
00156 self.__sock.sendall(self.program)
00157 self.robot_state = self.EXECUTING
00158
00159 def send_reset_program(self):
00160 self.__sock.sendall(RESET_PROGRAM)
00161 self.robot_state = self.READY_TO_PROGRAM
00162
00163 def disconnect(self):
00164 if self.__thread:
00165 self.__keep_running = False
00166 self.__thread.join()
00167 self.__thread = None
00168 if self.__sock:
00169 self.__sock.close()
00170 self.__sock = None
00171 self.last_state = None
00172 self.robot_state = self.DISCONNECTED
00173
00174 def ready_to_program(self):
00175 return self.robot_state in [self.READY_TO_PROGRAM, self.EXECUTING]
00176
00177 def __trigger_disconnected(self):
00178 log("Robot disconnected")
00179 self.robot_state = self.DISCONNECTED
00180 def __trigger_ready_to_program(self):
00181 rospy.loginfo("Robot ready to program")
00182 def __trigger_halted(self):
00183 log("Halted")
00184
00185 def __on_packet(self, buf):
00186 state = RobotState.unpack(buf)
00187 self.last_state = state
00188
00189
00190
00191
00192 if not state.robot_mode_data.real_robot_enabled:
00193 rospy.logfatal("Real robot is no longer enabled. Driver is fuxored")
00194 time.sleep(2)
00195 sys.exit(1)
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 msg = IOStates()
00209
00210 for i in range(0, 10):
00211 msg.digital_in_states.append(DigitalIn(i, (state.masterboard_data.digital_input_bits & (1<<i))>>i))
00212
00213 for i in range(0, 10):
00214 msg.digital_out_states.append(DigitalOut(i, (state.masterboard_data.digital_output_bits & (1<<i))>>i))
00215
00216 inp = state.masterboard_data.analog_input0 / MULT_analog_robotstate
00217 msg.analog_in_states.append(Analog(0, inp))
00218
00219 inp = state.masterboard_data.analog_input1 / MULT_analog_robotstate
00220 msg.analog_in_states.append(Analog(1, inp))
00221
00222 inp = state.masterboard_data.analog_output0 / MULT_analog_robotstate
00223 msg.analog_out_states.append(Analog(0, inp))
00224
00225 inp = state.masterboard_data.analog_output1 / MULT_analog_robotstate
00226 msg.analog_out_states.append(Analog(1, inp))
00227
00228 pub_io_states.publish(msg)
00229
00230
00231
00232 can_execute = (state.robot_mode_data.robot_mode in [RobotMode.READY, RobotMode.RUNNING])
00233 if self.robot_state == self.CONNECTED:
00234 if can_execute:
00235 self.__trigger_ready_to_program()
00236 self.robot_state = self.READY_TO_PROGRAM
00237 elif self.robot_state == self.READY_TO_PROGRAM:
00238 if not can_execute:
00239 self.robot_state = self.CONNECTED
00240 elif self.robot_state == self.EXECUTING:
00241 if not can_execute:
00242 self.__trigger_halted()
00243 self.robot_state = self.CONNECTED
00244
00245
00246 if len(state.unknown_ptypes) > 0:
00247 state.unknown_ptypes.sort()
00248 s_unknown_ptypes = [str(ptype) for ptype in state.unknown_ptypes]
00249 self.throttle_warn_unknown(1.0, "Ignoring unknown pkt type(s): %s. "
00250 "Please report." % ", ".join(s_unknown_ptypes))
00251
00252 def throttle_warn_unknown(self, period, msg):
00253 self.__dict__.setdefault('_last_hit', 0.0)
00254
00255 if (self._last_hit + period) <= rospy.get_time():
00256 self._last_hit = rospy.get_time()
00257 rospy.logwarn(msg)
00258
00259 def __run(self):
00260 while self.__keep_running:
00261 r, _, _ = select.select([self.__sock], [], [], self.TIMEOUT)
00262 if r:
00263 more = self.__sock.recv(4096)
00264 if more:
00265 self.__buf = self.__buf + more
00266
00267
00268 while len(self.__buf) >= 48:
00269
00270 packet_length, ptype = struct.unpack_from("!IB", self.__buf)
00271
00272 if len(self.__buf) >= packet_length:
00273 packet, self.__buf = self.__buf[:packet_length], self.__buf[packet_length:]
00274 self.__on_packet(packet)
00275 else:
00276 break
00277
00278 else:
00279 self.__trigger_disconnected()
00280 self.__keep_running = False
00281
00282 else:
00283 self.__trigger_disconnected()
00284 self.__keep_running = False
00285
00286
00287 class URConnectionRT(object):
00288 TIMEOUT = 1.0
00289
00290 DISCONNECTED = 0
00291 CONNECTED = 1
00292
00293 def __init__(self, hostname, port):
00294 self.__thread = None
00295 self.__sock = None
00296 self.robot_state = self.DISCONNECTED
00297 self.hostname = hostname
00298 self.port = port
00299 self.last_stateRT = None
00300
00301 def connect(self):
00302 if self.__sock:
00303 self.disconnect()
00304 self.__buf = ""
00305 self.robot_state = self.CONNECTED
00306 self.__sock = socket.create_connection((self.hostname, self.port))
00307 self.__keep_running = True
00308 self.__thread = threading.Thread(name="URConnectionRT", target=self.__run)
00309 self.__thread.daemon = True
00310 self.__thread.start()
00311
00312 def disconnect(self):
00313 if self.__thread:
00314 self.__keep_running = False
00315 self.__thread.join()
00316 self.__thread = None
00317 if self.__sock:
00318 self.__sock.close()
00319 self.__sock = None
00320 self.last_state = None
00321 self.robot_state = self.DISCONNECTED
00322
00323 def __trigger_disconnected(self):
00324 log("Robot disconnected")
00325 self.robot_state = self.DISCONNECTED
00326
00327 def __on_packet(self, buf):
00328 global last_joint_states, last_joint_states_lock
00329 now = rospy.get_rostime()
00330 stateRT = RobotStateRT.unpack(buf)
00331 self.last_stateRT = stateRT
00332
00333 msg = JointState()
00334 msg.header.stamp = now
00335 msg.header.frame_id = "From real-time state data"
00336 msg.name = joint_names
00337 msg.position = [0.0] * 6
00338 for i, q in enumerate(stateRT.q_actual):
00339 msg.position[i] = q + joint_offsets.get(joint_names[i], 0.0)
00340 msg.velocity = stateRT.qd_actual
00341 msg.effort = [0]*6
00342 pub_joint_states.publish(msg)
00343 with last_joint_states_lock:
00344 last_joint_states = msg
00345
00346 wrench_msg = WrenchStamped()
00347 wrench_msg.header.stamp = now
00348 wrench_msg.wrench.force.x = stateRT.tcp_force[0]
00349 wrench_msg.wrench.force.y = stateRT.tcp_force[1]
00350 wrench_msg.wrench.force.z = stateRT.tcp_force[2]
00351 wrench_msg.wrench.torque.x = stateRT.tcp_force[3]
00352 wrench_msg.wrench.torque.y = stateRT.tcp_force[4]
00353 wrench_msg.wrench.torque.z = stateRT.tcp_force[5]
00354 pub_wrench.publish(wrench_msg)
00355
00356
00357 def __run(self):
00358 while self.__keep_running:
00359 r, _, _ = select.select([self.__sock], [], [], self.TIMEOUT)
00360 if r:
00361 more = self.__sock.recv(4096)
00362 if more:
00363 self.__buf = self.__buf + more
00364
00365
00366 while len(self.__buf) >= 48:
00367
00368 packet_length = struct.unpack_from("!i", self.__buf)[0]
00369
00370 if len(self.__buf) >= packet_length:
00371 packet, self.__buf = self.__buf[:packet_length], self.__buf[packet_length:]
00372 self.__on_packet(packet)
00373 else:
00374 break
00375 else:
00376 self.__trigger_disconnected()
00377 self.__keep_running = False
00378
00379 else:
00380 self.__trigger_disconnected()
00381 self.__keep_running = False
00382
00383
00384 def setConnectedRobot(r):
00385 global connected_robot, connected_robot_lock
00386 with connected_robot_lock:
00387 connected_robot = r
00388 connected_robot_cond.notify()
00389
00390 def getConnectedRobot(wait=False, timeout=-1):
00391 started = time.time()
00392 with connected_robot_lock:
00393 if wait:
00394 while not connected_robot:
00395 if timeout >= 0 and time.time() > started + timeout:
00396 break
00397 connected_robot_cond.wait(0.2)
00398 return connected_robot
00399
00400
00401 class CommanderTCPHandler(SocketServer.BaseRequestHandler):
00402
00403 def recv_more(self):
00404 global last_joint_states, last_joint_states_lock
00405 while True:
00406 r, _, _ = select.select([self.request], [], [], 0.2)
00407 if r:
00408 more = self.request.recv(4096)
00409 if not more:
00410 raise EOF("EOF on recv")
00411 return more
00412 else:
00413 now = rospy.get_rostime()
00414 if last_joint_states and \
00415 last_joint_states.header.stamp < now - rospy.Duration(1.0):
00416 rospy.logerr("Stopped hearing from robot (last heard %.3f sec ago). Disconnected" % \
00417 (now - last_joint_states.header.stamp).to_sec())
00418 raise EOF()
00419
00420 def handle(self):
00421 self.__socket_lock = threading.Lock()
00422 setConnectedRobot(self)
00423 print "Handling a request"
00424 try:
00425 buf = self.recv_more()
00426 if not buf: return
00427
00428 while True:
00429
00430
00431
00432 mtype = struct.unpack_from("!i", buf, 0)[0]
00433 buf = buf[4:]
00434
00435
00436 if mtype == MSG_OUT:
00437
00438 i = buf.find("~")
00439 while i < 0:
00440 buf = buf + self.recv_more()
00441 i = buf.find("~")
00442 if len(buf) > 2000:
00443 raise Exception("Probably forgot to terminate a string: %s..." % buf[:150])
00444 s, buf = buf[:i], buf[i+1:]
00445 log("Out: %s" % s)
00446
00447 elif mtype == MSG_QUIT:
00448 print "Quitting"
00449 raise EOF("Received quit")
00450 elif mtype == MSG_WAYPOINT_FINISHED:
00451 while len(buf) < 4:
00452 buf = buf + self.recv_more()
00453 waypoint_id = struct.unpack_from("!i", buf, 0)[0]
00454 buf = buf[4:]
00455 print "Waypoint finished (not handled)"
00456 else:
00457 raise Exception("Unknown message type: %i" % mtype)
00458
00459 if not buf:
00460 buf = buf + self.recv_more()
00461 except EOF, ex:
00462 print "Connection closed (command):", ex
00463 setConnectedRobot(None)
00464
00465 def __send_message(self, data):
00466 """
00467 Send a message to the robot.
00468
00469 The message is given as a list of integers that will be packed
00470 as 4 bytes each in network byte order (big endian).
00471
00472 A lock is acquired before sending the message to prevent race conditions.
00473
00474 :param data: list of int, the data to send
00475 """
00476 buf = struct.pack("!%ii" % len(data), *data)
00477 with self.__socket_lock:
00478 self.request.send(buf)
00479
00480 def send_quit(self):
00481 self.__send_message([MSG_QUIT])
00482
00483 def send_servoj(self, waypoint_id, q_actual, t):
00484 assert(len(q_actual) == 6)
00485 q_robot = [0.0] * 6
00486 for i, q in enumerate(q_actual):
00487 q_robot[i] = q - joint_offsets.get(joint_names[i], 0.0)
00488 params = [MSG_SERVOJ, waypoint_id] + \
00489 [MULT_jointstate * qq for qq in q_robot] + \
00490 [MULT_time * t]
00491 self.__send_message(params)
00492
00493
00494 def send_payload(self,payload):
00495 self.__send_message([MSG_SET_PAYLOAD, payload * MULT_payload])
00496
00497
00498 def set_digital_out(self, pinnum, value):
00499 self.__send_message([MSG_SET_DIGITAL_OUT, pinnum, value])
00500 time.sleep(IO_SLEEP_TIME)
00501
00502 def set_analog_out(self, pinnum, value):
00503 self.__send_message([MSG_SET_ANALOG_OUT, pinnum, value * MULT_analog])
00504 time.sleep(IO_SLEEP_TIME)
00505
00506 def set_tool_voltage(self, value):
00507 self.__send_message([MSG_SET_TOOL_VOLTAGE, value, 0])
00508 time.sleep(IO_SLEEP_TIME)
00509
00510 def set_flag(self, pin, val):
00511 self.__send_message([MSG_SET_FLAG, pin, val])
00512
00513 time.sleep(IO_SLEEP_TIME)
00514
00515 def send_stopj(self):
00516 self.__send_message([MSG_STOPJ])
00517
00518 def set_waypoint_finished_cb(self, cb):
00519 self.waypoint_finished_cb = cb
00520
00521
00522 def get_joint_states(self):
00523 global last_joint_states, last_joint_states_lock
00524 return last_joint_states
00525
00526
00527 class TCPServer(SocketServer.TCPServer):
00528 allow_reuse_address = True
00529 timeout = 5
00530
00531
00532
00533 def joinAll(threads):
00534 while any(t.isAlive() for t in threads):
00535 for t in threads:
00536 t.join(0.2)
00537
00538
00539
00540 def get_segment_duration(traj, index):
00541 if index == 0:
00542 return traj.points[0].time_from_start.to_sec()
00543 return (traj.points[index].time_from_start - traj.points[index-1].time_from_start).to_sec()
00544
00545
00546
00547 def reorder_traj_joints(traj, joint_names):
00548 order = [traj.joint_names.index(j) for j in joint_names]
00549
00550 new_points = []
00551 for p in traj.points:
00552 new_points.append(JointTrajectoryPoint(
00553 positions = [p.positions[i] for i in order],
00554 velocities = [p.velocities[i] for i in order] if p.velocities else [],
00555 accelerations = [p.accelerations[i] for i in order] if p.accelerations else [],
00556 time_from_start = p.time_from_start))
00557 traj.joint_names = joint_names
00558 traj.points = new_points
00559
00560 def interp_cubic(p0, p1, t_abs):
00561 T = (p1.time_from_start - p0.time_from_start).to_sec()
00562 t = t_abs - p0.time_from_start.to_sec()
00563 q = [0] * 6
00564 qdot = [0] * 6
00565 qddot = [0] * 6
00566 for i in range(len(p0.positions)):
00567 a = p0.positions[i]
00568 b = p0.velocities[i]
00569 c = (-3*p0.positions[i] + 3*p1.positions[i] - 2*T*p0.velocities[i] - T*p1.velocities[i]) / T**2
00570 d = (2*p0.positions[i] - 2*p1.positions[i] + T*p0.velocities[i] + T*p1.velocities[i]) / T**3
00571
00572 q[i] = a + b*t + c*t**2 + d*t**3
00573 qdot[i] = b + 2*c*t + 3*d*t**2
00574 qddot[i] = 2*c + 6*d*t
00575 return JointTrajectoryPoint(positions=q, velocities=qdot, accelerations=qddot, time_from_start=rospy.Duration(t_abs))
00576
00577
00578
00579 def sample_traj(traj, t):
00580
00581 if t <= 0.0:
00582 return copy.deepcopy(traj.points[0])
00583
00584 if t >= traj.points[-1].time_from_start.to_sec():
00585 return copy.deepcopy(traj.points[-1])
00586
00587
00588 i = 0
00589 while traj.points[i+1].time_from_start.to_sec() < t:
00590 i += 1
00591 return interp_cubic(traj.points[i], traj.points[i+1], t)
00592
00593 def traj_is_finite(traj):
00594 for pt in traj.points:
00595 for p in pt.positions:
00596 if math.isinf(p) or math.isnan(p):
00597 return False
00598 for v in pt.velocities:
00599 if math.isinf(v) or math.isnan(v):
00600 return False
00601 return True
00602
00603 def has_limited_velocities(traj):
00604 for p in traj.points:
00605 for v in p.velocities:
00606 if math.fabs(v) > max_velocity:
00607 return False
00608 return True
00609
00610 def has_velocities(traj):
00611 for p in traj.points:
00612 if len(p.velocities) != len(p.positions):
00613 return False
00614 return True
00615
00616 def within_tolerance(a_vec, b_vec, tol_vec):
00617 for a, b, tol in zip(a_vec, b_vec, tol_vec):
00618 if abs(a - b) > tol:
00619 return False
00620 return True
00621
00622 class URServiceProvider(object):
00623 def __init__(self, robot):
00624 self.robot = robot
00625 rospy.Service('ur_driver/setPayload', SetPayload, self.setPayload)
00626
00627 def set_robot(self, robot):
00628 self.robot = robot
00629
00630 def setPayload(self, req):
00631 if req.payload < min_payload or req.payload > max_payload:
00632 print 'ERROR: Payload ' + str(req.payload) + ' out of bounds (' + str(min_payload) + ', ' + str(max_payload) + ')'
00633 return False
00634
00635 if self.robot:
00636 self.robot.send_payload(req.payload)
00637 else:
00638 return False
00639 return True
00640
00641 class URTrajectoryFollower(object):
00642 RATE = 0.02
00643 def __init__(self, robot, goal_time_tolerance=None):
00644 self.goal_time_tolerance = goal_time_tolerance or rospy.Duration(0.0)
00645 self.joint_goal_tolerances = [0.05, 0.05, 0.05, 0.05, 0.05, 0.05]
00646 self.following_lock = threading.Lock()
00647 self.T0 = time.time()
00648 self.robot = robot
00649 self.server = actionlib.ActionServer("follow_joint_trajectory",
00650 FollowJointTrajectoryAction,
00651 self.on_goal, self.on_cancel, auto_start=False)
00652
00653 self.goal_handle = None
00654 self.traj = None
00655 self.traj_t0 = 0.0
00656 self.first_waypoint_id = 10
00657 self.tracking_i = 0
00658 self.pending_i = 0
00659 self.last_point_sent = True
00660
00661 self.update_timer = rospy.Timer(rospy.Duration(self.RATE), self._update)
00662
00663 def set_robot(self, robot):
00664
00665 if self.goal_handle:
00666 self.goal_handle.set_canceled()
00667 self.goal_handle = None
00668 self.traj = None
00669 self.robot = robot
00670 if self.robot:
00671 self.init_traj_from_robot()
00672
00673
00674
00675 def init_traj_from_robot(self):
00676 if not self.robot: raise Exception("No robot connected")
00677
00678 state = self.robot.get_joint_states()
00679 while not state:
00680 time.sleep(0.1)
00681 state = self.robot.get_joint_states()
00682 self.traj_t0 = time.time()
00683 self.traj = JointTrajectory()
00684 self.traj.joint_names = joint_names
00685 self.traj.points = [JointTrajectoryPoint(
00686 positions = state.position,
00687 velocities = [0] * 6,
00688 accelerations = [0] * 6,
00689 time_from_start = rospy.Duration(0.0))]
00690
00691 def start(self):
00692 self.init_traj_from_robot()
00693 self.server.start()
00694 print "The action server for this driver has been started"
00695
00696 def on_goal(self, goal_handle):
00697 log("on_goal")
00698
00699
00700 if not self.robot:
00701 rospy.logerr("Received a goal, but the robot is not connected")
00702 goal_handle.set_rejected()
00703 return
00704
00705
00706 if set(goal_handle.get_goal().trajectory.joint_names) != set(joint_names):
00707 rospy.logerr("Received a goal with incorrect joint names: (%s)" % \
00708 ', '.join(goal_handle.get_goal().trajectory.joint_names))
00709 goal_handle.set_rejected()
00710 return
00711
00712 if not traj_is_finite(goal_handle.get_goal().trajectory):
00713 rospy.logerr("Received a goal with infinites or NaNs")
00714 goal_handle.set_rejected(text="Received a goal with infinites or NaNs")
00715 return
00716
00717
00718 if not has_velocities(goal_handle.get_goal().trajectory):
00719 rospy.logerr("Received a goal without velocities")
00720 goal_handle.set_rejected(text="Received a goal without velocities")
00721 return
00722
00723
00724 if not has_limited_velocities(goal_handle.get_goal().trajectory):
00725 message = "Received a goal with velocities that are higher than %f" % max_velocity
00726 rospy.logerr(message)
00727 goal_handle.set_rejected(text=message)
00728 return
00729
00730
00731 reorder_traj_joints(goal_handle.get_goal().trajectory, joint_names)
00732
00733 with self.following_lock:
00734 if self.goal_handle:
00735
00736 self.goal_handle.set_canceled()
00737 self.first_waypoint_id += len(self.goal_handle.get_goal().trajectory.points)
00738 self.goal_handle = None
00739
00740
00741 now = time.time()
00742 point0 = sample_traj(self.traj, now - self.traj_t0)
00743 point0.time_from_start = rospy.Duration(0.0)
00744 goal_handle.get_goal().trajectory.points.insert(0, point0)
00745 self.traj_t0 = now
00746
00747
00748 self.goal_handle = goal_handle
00749 self.traj = goal_handle.get_goal().trajectory
00750 self.goal_handle.set_accepted()
00751
00752 def on_cancel(self, goal_handle):
00753 log("on_cancel")
00754 if goal_handle == self.goal_handle:
00755 with self.following_lock:
00756
00757 STOP_DURATION = 0.5
00758 now = time.time()
00759 point0 = sample_traj(self.traj, now - self.traj_t0)
00760 point0.time_from_start = rospy.Duration(0.0)
00761 point1 = sample_traj(self.traj, now - self.traj_t0 + STOP_DURATION)
00762 point1.velocities = [0] * 6
00763 point1.accelerations = [0] * 6
00764 point1.time_from_start = rospy.Duration(STOP_DURATION)
00765 self.traj_t0 = now
00766 self.traj = JointTrajectory()
00767 self.traj.joint_names = joint_names
00768 self.traj.points = [point0, point1]
00769
00770 self.goal_handle.set_canceled()
00771 self.goal_handle = None
00772 else:
00773 goal_handle.set_canceled()
00774
00775 last_now = time.time()
00776 def _update(self, event):
00777 if self.robot and self.traj:
00778 now = time.time()
00779 if (now - self.traj_t0) <= self.traj.points[-1].time_from_start.to_sec():
00780 self.last_point_sent = False
00781 setpoint = sample_traj(self.traj, now - self.traj_t0)
00782 try:
00783 self.robot.send_servoj(999, setpoint.positions, 4 * self.RATE)
00784 except socket.error:
00785 pass
00786
00787 elif not self.last_point_sent:
00788
00789
00790
00791
00792 last_point = self.traj.points[-1]
00793 state = self.robot.get_joint_states()
00794 position_in_tol = within_tolerance(state.position, last_point.positions, self.joint_goal_tolerances)
00795
00796
00797 if not position_in_tol:
00798 rospy.logwarn("Trajectory time exceeded and current robot state not at goal, last point required")
00799 rospy.logwarn("Current trajectory time: %s, last point time: %s" % \
00800 (now - self.traj_t0, self.traj.points[-1].time_from_start.to_sec()))
00801 rospy.logwarn("Desired: %s\nactual: %s\nvelocity: %s" % \
00802 (last_point.positions, state.position, state.velocity))
00803 setpoint = sample_traj(self.traj, self.traj.points[-1].time_from_start.to_sec())
00804
00805 try:
00806 self.robot.send_servoj(999, setpoint.positions, 4 * self.RATE)
00807 self.last_point_sent = True
00808 except socket.error:
00809 pass
00810
00811 else:
00812 if self.goal_handle:
00813 last_point = self.traj.points[-1]
00814 state = self.robot.get_joint_states()
00815 position_in_tol = within_tolerance(state.position, last_point.positions, [0.1]*6)
00816 velocity_in_tol = within_tolerance(state.velocity, last_point.velocities, [0.05]*6)
00817 if position_in_tol and velocity_in_tol:
00818
00819 self.goal_handle.set_succeeded()
00820 self.goal_handle = None
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832 def load_joint_offsets(joint_names):
00833 from lxml import etree
00834 robot_description = rospy.get_param("robot_description")
00835 doc = etree.fromstring(robot_description)
00836
00837
00838
00839 expr = "/robot/joint[@name=$name]/calibration_offset"
00840 result = {}
00841 for joint in joint_names:
00842 joint_elt = doc.xpath(expr, name=joint)
00843 if len(joint_elt) == 1:
00844 calibration_offset = float(joint_elt[0].get("value"))
00845 result[joint] = calibration_offset
00846 rospy.loginfo("Found calibration offset for joint \"%s\": %.4f" % (joint, calibration_offset))
00847 elif len(joint_elt) > 1:
00848 rospy.logerr("Too many joints matched on \"%s\". Please report to package maintainer(s)." % joint)
00849 else:
00850 rospy.logwarn("No calibration offset for joint \"%s\"" % joint)
00851 return result
00852
00853 def get_my_ip(robot_ip, port):
00854 s = socket.create_connection((robot_ip, port))
00855 tmp = s.getsockname()[0]
00856 s.close()
00857 return tmp
00858
00859 def handle_set_io(req):
00860 r = getConnectedRobot(wait=False)
00861 if r:
00862 if req.fun == req.FUN_SET_DIGITAL_OUT:
00863 r.set_digital_out(req.pin, req.state)
00864 return True
00865 elif req.fun == req.FUN_SET_FLAG:
00866 r.set_flag(req.pin, req.state)
00867 return True
00868 elif req.fun == req.FUN_SET_ANALOG_OUT:
00869 r.set_analog_out(req.pin, req.state)
00870 return True
00871 elif req.fun == req.FUN_SET_TOOL_VOLTAGE:
00872 r.set_tool_voltage(req.pin)
00873 return True
00874 else:
00875 raise ROSServiceException("Robot not connected")
00876
00877 def set_io_server():
00878 s= rospy.Service('set_io', SetIO, handle_set_io)
00879
00880 def reconfigure_callback(config, level):
00881 global prevent_programming
00882 prevent_programming = config.prevent_programming
00883
00884 return config
00885
00886 def main():
00887 rospy.init_node('ur_driver', disable_signals=True)
00888 if rospy.get_param("use_sim_time", False):
00889 rospy.logwarn("use_sim_time is set!!!")
00890
00891 global prevent_programming
00892 reconfigure_srv = Server(URDriverConfig, reconfigure_callback)
00893
00894 prefix = rospy.get_param("~prefix", "")
00895 print "Setting prefix to %s" % prefix
00896 global joint_names
00897 joint_names = [prefix + name for name in JOINT_NAMES]
00898
00899
00900 parser = optparse.OptionParser(usage="usage: %prog robot_hostname [reverse_port]")
00901 (options, args) = parser.parse_args(rospy.myargv()[1:])
00902 if len(args) < 1:
00903 parser.error("You must specify the robot hostname")
00904 elif len(args) == 1:
00905 robot_hostname = args[0]
00906 reverse_port = DEFAULT_REVERSE_PORT
00907 elif len(args) == 2:
00908 robot_hostname = args[0]
00909 reverse_port = int(args[1])
00910 if not (0 <= reverse_port <= 65535):
00911 parser.error("You entered an invalid port number")
00912 else:
00913 parser.error("Wrong number of parameters")
00914
00915
00916 global joint_offsets
00917 joint_offsets = load_joint_offsets(joint_names)
00918 if len(joint_offsets) > 0:
00919 rospy.loginfo("Loaded calibration offsets from urdf: %s" % joint_offsets)
00920 else:
00921 rospy.loginfo("No calibration offsets loaded from urdf")
00922
00923
00924
00925 global max_velocity
00926 max_velocity = rospy.get_param("~max_velocity", MAX_VELOCITY)
00927 rospy.loginfo("Max velocity accepted by ur_driver: %s [rad/s]" % max_velocity)
00928
00929
00930 global min_payload
00931 min_payload = rospy.get_param("~min_payload", MIN_PAYLOAD)
00932
00933 global max_payload
00934 max_payload = rospy.get_param("~max_payload", MAX_PAYLOAD)
00935 rospy.loginfo("Bounds for Payload: [%s, %s]" % (min_payload, max_payload))
00936
00937
00938
00939 server = TCPServer(("", reverse_port), CommanderTCPHandler)
00940 thread_commander = threading.Thread(name="CommanderHandler", target=server.serve_forever)
00941 thread_commander.daemon = True
00942 thread_commander.start()
00943
00944 with open(roslib.packages.get_pkg_dir('ur_driver') + '/prog') as fin:
00945 program = fin.read() % {"driver_hostname": get_my_ip(robot_hostname, PORT), "driver_reverseport": reverse_port}
00946 connection = URConnection(robot_hostname, PORT, program)
00947 connection.connect()
00948 connection.send_reset_program()
00949
00950 connectionRT = URConnectionRT(robot_hostname, RT_PORT)
00951 connectionRT.connect()
00952
00953 set_io_server()
00954
00955 service_provider = None
00956 action_server = None
00957 try:
00958 while not rospy.is_shutdown():
00959
00960 if getConnectedRobot(wait=False):
00961 time.sleep(0.2)
00962 try:
00963 prevent_programming = rospy.get_param("~prevent_programming")
00964 update = {'prevent_programming': prevent_programming}
00965 reconfigure_srv.update_configuration(update)
00966 except KeyError, ex:
00967 print "Parameter 'prevent_programming' not set. Value: " + str(prevent_programming)
00968 pass
00969 if prevent_programming:
00970 print "Programming now prevented"
00971 connection.send_reset_program()
00972 else:
00973 print "Disconnected. Reconnecting"
00974 if action_server:
00975 action_server.set_robot(None)
00976
00977 rospy.loginfo("Programming the robot")
00978 while True:
00979
00980 while not connection.ready_to_program():
00981 print "Waiting to program"
00982 time.sleep(1.0)
00983 try:
00984 prevent_programming = rospy.get_param("~prevent_programming")
00985 update = {'prevent_programming': prevent_programming}
00986 reconfigure_srv.update_configuration(update)
00987 except KeyError, ex:
00988 print "Parameter 'prevent_programming' not set. Value: " + str(prevent_programming)
00989 pass
00990 connection.send_program()
00991
00992 r = getConnectedRobot(wait=True, timeout=1.0)
00993 if r:
00994 break
00995 rospy.loginfo("Robot connected")
00996
00997
00998 if service_provider:
00999 service_provider.set_robot(r)
01000 else:
01001 service_provider = URServiceProvider(r)
01002
01003 if action_server:
01004 action_server.set_robot(r)
01005 else:
01006 action_server = URTrajectoryFollower(r, rospy.Duration(1.0))
01007 action_server.start()
01008
01009 except KeyboardInterrupt:
01010 try:
01011 r = getConnectedRobot(wait=False)
01012 rospy.signal_shutdown("KeyboardInterrupt")
01013 if r: r.send_quit()
01014 except:
01015 pass
01016 raise
01017
01018 if __name__ == '__main__': main()