ur5demo/ur5controller.py

128 lines
3.9 KiB
Python

import urx, math, math3d
class UR5Exception(Exception):
pass
class DemoController(object):
"""Implements control of the UR5 in cylinder coordinates (corresponding to attached table).
-Checks bounds of the arc section
-Methods for placing blocks
"""
def __init__(self, config):
"""Initializes the controller with parameters specified in config"""
self.debug = config.DEBUG
try:
self.robot = urx.Robot(config.UR5_IP, useRTInterface=config.USE_FORCE_MONITOR) #TODO or hostname
except Exception, e:
raise UR5Exception('Robot initiation failed: %s' % str(e))
# Set cylinder parameters
self.quadrant = config.TABLE_QUADRANT
self.phi = self.quadrant*math.pi/2
self.cyl_offset = config.TABLE_ORIGO_OFFSET
self.cyl_ox = self.cyl_offset*math.cos(self.phi)
self.cyl_oy = self.cyl_offset*math.sin(self.phi)
self.r_min = config.R_MIN
self.r_max = config.R_MAX
self.theta_min = config.TABLE_EDGE_LEFT
self.theta_max = config.TABLE_EDGE_RIGHT
self.z_min = config.Z_MIN
self.z_max = config.Z_MAX
self.j_home = config.QUADRANT_JOINT_CONFIG
self.vel = config.VELOCITY
self.acc = config.ACCELERATION
self.dec = config.DECELERATION
# Move to reference coordinate system base
self.set_pose_home()
# Set reference coordinate system parameters
csys = math3d.Transform()
csys.orient.rotate_zb(self.phi)
self.robot.set_csys("csys", csys)
self.trans_base = self.robot.get_transform()
self.cyl_ox = self.cyl_offset
self.cyl_oy = 0
def set_pose_home(self):
"""Move to "home" configuration. The resulting pose ensures correct orientation."""
try:
self.robot.movej(self.j_home, acc=0.1, vel=0.5, radius=0, wait=True, relative=False)
pose = self.robot.getl()
pose[0] = self.r_min*math.cos(self.phi) + self.cyl_ox
pose[1] = self.r_min*math.sin(self.phi) + self.cyl_oy
pose[2] = self.z_min
self.robot.movel(pose, acc=0.1, vel=0.2, radius=0, wait=True, relative=False)
self.current_cyl = (self.r_min, 0, self.z_min)
except Exception, e:
raise UR5Exception('Move to home configuration failed: %s' % str(e))
def cylinder2pose(self, r, theta, z):
"""Translate table cylinder coordinates to robot cartesian pose.
(r, theta) is given in TABLE coordinates.
"""
trans = math3d.Transform(self.trans_base) #deep copy
trans.orient.rotate_zb(theta)
trans.pos = math3d.Vector(r*math.cos(theta) + self.cyl_ox,
r*math.sin(theta) + self.cyl_oy,
z)
return trans.pose_vector.tolist()
def movel(self, r, theta, z):
pose = self.cylinder2pose(r, theta, z)
self.robot.movel(pose, acc=self.acc, vel=self.vel, radius=0, wait=True, relative=False)
self.current_cyl = (r, theta, z)
def movec(self, r, theta, z):
#Note: r should be the same.
curr_theta = self.current_cyl[1]
pose_via = self.cylinder2pose(r, curr_theta+(theta-curr_theta)/2, z)
pose = self.cylinder2pose(r, theta, z)
self.robot.movec(pose_via, pose, acc=self.acc, vel=self.vel, radius=0, wait=True)
self.current_cyl = (r, theta, z)
def movec_hax(self, r, theta, z):
"""Since movec is unreliable in reaching the end pose: linearize the arc."""
curr_r, curr_theta, curr_z = self.current_cyl
dtheta = theta - curr_theta
if dtheta > 0:
theta_incr = math.pi/41
else:
theta_incr = -math.pi/41
if abs(dtheta) < abs(theta_incr):
self.movel(r, theta, z)
return
pose_list = []
segments = int(math.floor(dtheta/theta_incr))
r_incr = (r-curr_r)/(segments+1)
z_incr = (z-curr_z)/(segments+1)
for i in range(1, segments+1):
pose_list.append(self.cylinder2pose(curr_r + i*r_incr,
curr_theta + i*theta_incr,
curr_z + i*z_incr))
pose_list.append(self.cylinder2pose(r, theta, z))
#debug
if self.debug:
print "pose list for movec_hax"
for p in pose_list:
print [('%.3f' % i) for i in p]
self.robot.movels(pose_list, acc=self.acc, vel=self.vel, radius=0.05, wait=True)
self.current_cyl = (r, theta, z)
def cleanup(self):
self.robot.cleanup()