--- a +++ b/URBasic/manipulation.py @@ -0,0 +1,1212 @@ +import math +from numpy import * + +### HELPER FUNCTIONS ### +def randomVec(x): + ''' + Generates a vector of length x, each component being a random float b/w -10 and 10 + ''' + return random.uniform(-10,10,(x,1)) + + +def randomUnitAxisAngle(): + ''' + Generates a random unit axis and an angle + ''' + # Random longitude + u = random.uniform(0, 1) + longitude = 2*math.pi*u + + # Random latitude + v = random.uniform(0, 1) + latitude = 2*math.pi*v + + # Random unit rotation axis + axis = zeros((3,1)) + axis[0] = math.cos(latitude)*math.cos(longitude) + axis[1] = math.cos(latitude)*math.sin(longitude) + axis[2] = math.sin(latitude) + + # Random angle b/w 0 and 2pi + theta = 2*math.pi*random.uniform(0, 1) + + return axis, theta + + +def normalize(v): + ''' + Returns the normalized version of the vector v + ''' + norm = linalg.norm(v) + if norm == 0: + return v + return v/norm + + +def is_identity_matrix(M): + ''' + Returns True if input M is close to an identity matrix + ''' + if len(M) != len(M[0]): + return False + + c = list() + for i, row in enumerate(M): + for j, val in enumerate(row): + if i==j: + if val < 1.001 and val > 0.999: + c.append(True) + else: + c.append(False) + else: + if abs(val) < 0.001: + c.append(True) + else: + c.append(False) + + return all(c) + + +def is_rot_matrix(R): + ''' + Returns True if input R is a valid rotation matrix. + ''' + R = asarray(R) + return is_identity_matrix(dot(R.T,R)) and (abs(linalg.det(R)-1) < 0.001) + + +### MAIN FUNCTIONS ### +def RotInv(R): + ''' + Takes a rotation matrix belonging to SO(3) and returns its inverse. + Example: + + R = [[.707,-.707,0],[.707,.707,0],[0,0,1]] + RotInv(R) + >> array([[ 0.707, 0.707, 0. ], + [-0.707, 0.707, 0. ], + [ 0. , 0. , 1. ]]) + ''' + R = asarray(R) + assert is_rot_matrix(R), 'Not a valid rotation matrix' + + return R.T + + +def VecToso3(w): + ''' + Takes a 3-vector representing angular velocity and returns the 3x3 skew-symmetric matrix version, an element + of so(3). + Example: + + w = [2, 1, -4] + VecToso3(w) + >> array([[ 0, 4, 1], + [-4, 0, -2], + [-1, 2, 0]]) + ''' + w = asarray(w) + assert len(w) == 3, 'Not a 3-vector' + + w = w.flatten() + w_so3mat = array([[0, -w[2], w[1]], [w[2], 0, -w[0]], [-w[1], w[0], 0]]) + return w_so3mat + + +def so3ToVec(w_so3mat): + ''' + Takes a 3x3 skew-symmetric matrix (an element of so(3)) and returns the corresponding 3-vector. + Example: + + w_so3mat = [[ 0, 4, 1],[-4, 0, -2],[-1, 2, 0]] + so3ToVec(w_so3mat) + >> array([[ 2], + [ 1], + [-4]]) + ''' + w_so3mat = asarray(w_so3mat) + assert w_so3mat.shape == (3,3), 'Not a 3x3 matrix' + + w = array([[w_so3mat[2,1]], [w_so3mat[0,2]], [w_so3mat[1,0]]]) + return w + + +def AxisAng3(r): + ''' + Takes a 3-vector of exp coords r = w_unit*theta and returns w_unit and theta. + Example: + + r = [2, 1, -4] + w_unit, theta = AxisAng3(r) + w_unit + >> array([ 0.43643578, 0.21821789, -0.87287156]) + theta + >> 4.5825756949558398 + ''' + r = asarray(r) + assert len(r) == 3, 'Not a 3-vector' + + theta = linalg.norm(r) + w_unit = normalize(r) + + return w_unit, theta + + +def MatrixExp3(r): + ''' + Takes a 3-vector of exp coords r = w_unit*theta and returns the corresponding + rotation matrix R (an element of SO(3)). + Example: + + r = [2, 1, -4] + MatrixExp3(r) + >> array([[ 0.08568414, -0.75796072, -0.64664811], + [ 0.97309386, -0.07566572, 0.2176305 ], + [-0.21388446, -0.64789679, 0.73108357]]) + ''' + r = asarray(r) + assert len(r) == 3, 'Not a 3-vector' + + w_unit, theta = AxisAng3(r) + w_so3mat = VecToso3(w_unit) + + R = identity(3) + math.sin(theta)*w_so3mat + (1-math.cos(theta))*dot(w_so3mat, w_so3mat) + assert is_rot_matrix(R), 'Did not produce a valid rotation matrix' + return R + + +def MatrixLog3(R): + ''' + Takes a rotation matrix R and returns the corresponding 3-vector of exp coords r = w_unit*theta. + Example: + + R = [[.707,-.707,0],[.707,.707,0],[0,0,1]] + MatrixLog3(R) + >> array([[ 0. ], + [ 0. ], + [ 0.78554916]]) + ''' + R = asarray(R) + assert is_rot_matrix(R), 'Not a valid rotation matrix' + + if is_identity_matrix(R): + return zeros((3,1)) + + if trace(R) > -1.001 and trace(R) < -0.999: + theta = math.pi + c = max(diag(R)) + if c == R[2,2]: + w_unit = array([[R[0,2]],[R[1,2]],[1+c]])*1/((2*(1+c))**0.5) + return w_unit*theta + elif c == R[1,1]: + w_unit = array([[R[0,1]],[1+c],[R[2,1]]])*1/((2*(1+c))**0.5) + return w_unit*theta + elif c == R[0,0]: + w_unit = array([[1+c],[R[1,0]],[R[2,0]]])*1/((2*(1+c))**0.5) + return w_unit*theta + + theta = math.acos((trace(R)-1)/2) + w_so3mat = (R - R.T)/(2*math.sin(theta)) + w_unit = normalize(so3ToVec(w_so3mat)) + return w_unit*theta + + +def RpToTrans(R,p): + ''' + Takes a rotation matrix R and a point (3-vector) p, and returns the corresponding + 4x4 transformation matrix T, an element of SE(3). + Example: + + R = [[.707,-.707,0],[.707,.707,0],[0,0,1]] + p = [5,-4,9] + RpToTrans(R,p) + >> array([[ 0.707, -0.707, 0. , 5. ], + [ 0.707, 0.707, 0. , -4. ], + [ 0. , 0. , 1. , 9. ], + [ 0. , 0. , 0. , 1. ]]) + ''' + p = asarray(p) + R = asarray(R) + assert len(p) == 3, "Point not a 3-vector" + assert is_rot_matrix(R), "R not a valid rotation matrix" + + p.shape = (3,1) + T = vstack((hstack((R,p)), array([0,0,0,1]))) + return T + + +def TransToRp(T): + ''' + Takes a transformation matrix T and returns the corresponding R and p. + Example: + + T = [[0.707,-0.707,0,5],[0.707,0.707,0,-4],[0,0,1,9],[0,0,0,1]] + R, p = TransToRp(T) + R + >> array([[ 0.707, -0.707, 0. ], + [ 0.707, 0.707, 0. ], + [ 0. , 0. , 1. ]]) + p + >> array([[ 5.], + [-4.], + [ 9.]]) + ''' + T = asarray(T) + assert T.shape == (4,4), "Input not a 4x4 matrix" + + R = T[:3,:3] + assert is_rot_matrix(R), "Input not a valid transformation matrix" + + assert allclose([0,0,0,1],T[-1],atol=1e-03), "Last row of homogenous T matrix should be [0,0,0,1]" + + p = T[:3,-1] + p.shape = (3,1) + + return R, p + + +def TransInv(T): + ''' + Returns inverse of transformation matrix T. + Example: + + T = [[0.707,-0.707,0,5],[0.707,0.707,0,-4],[0,0,1,9],[0,0,0,1]] + TransInv(T) + >> array([[ 0.707, 0.707, 0. , -0.707], + [-0.707, 0.707, 0. , 6.363], + [ 0. , 0. , 1. , -9. ], + [ 0. , 0. , 0. , 1. ]]) + ''' + T = asarray(T) + R, p = TransToRp(T) + + T_inv = RpToTrans(RotInv(R), dot(-RotInv(R),p)) + return T_inv + + +def VecTose3(V): + ''' + Takes a 6-vector (representing spatial velocity) and returns the corresponding 4x4 matrix, + an element of se(3). + Example: + + V = [3,2,5,-3,7,0] + VecTose3(V) + >> array([[ 0., -5., 2., -3.], + [ 5., 0., -3., 7.], + [-2., 3., 0., 0.], + [ 0., 0., 0., 0.]]) + ''' + V = asarray(V) + assert len(V) == 6, "Input not a 6-vector" + + V.shape = (6,1) + w = V[:3] + w_so3mat = VecToso3(w) + v = V[3:] + V_se3mat = vstack((hstack((w_so3mat,v)), zeros(4))) + return V_se3mat + + +def se3ToVec(V_se3mat): + ''' + Takes an element of se(3) and returns the corresponding (6-vector) spatial velocity. + Example: + + V_se3mat = [[ 0., -5., 2., -3.], + [ 5., 0., -3., 7.], + [-2., 3., 0., 0.], + [ 0., 0., 0., 0.]] + se3ToVec(V_se3mat) + >> array([[ 3.], + [ 2.], + [ 5.], + [-3.], + [ 7.], + [ 0.]]) + ''' + V_se3mat = asarray(V_se3mat) + assert V_se3mat.shape == (4,4), "Matrix is not 4x4" + + w_so3mat = V_se3mat[:3,:3] + w = so3ToVec(w_so3mat) + + v = V_se3mat[:3,-1] + v.shape = (3,1) + + V = vstack((w,v)) + return V + + +def Adjoint(T): + ''' + Takes a transformation matrix T and returns the 6x6 adjoint representation [Ad_T] + Example: + + T = [[0.707,-0.707,0,5],[0.707,0.707,0,-4],[0,0,1,9],[0,0,0,1]] + Adjoint(T) + >> array([[ 0.707, -0.707, 0. , 0. , 0. , 0. ], + [ 0.707, 0.707, 0. , 0. , 0. , 0. ], + [ 0. , 0. , 1. , 0. , 0. , 0. ], + [-6.363, -6.363, -4. , 0.707, -0.707, 0. ], + [ 6.363, -6.363, -5. , 0.707, 0.707, 0. ], + [ 6.363, 0.707, 0. , 0. , 0. , 1. ]]) + ''' + T = asarray(T) + assert T.shape == (4,4), "Input not a 4x4 matrix" + + R, p = TransToRp(T) + p = p.flatten() + p_skew = array([[0, -p[2], p[1]], [p[2], 0, -p[0]], [-p[1], p[0], 0]]) + + ad1 = vstack((R, dot(p_skew,R))) + ad2 = vstack((zeros((3,3)),R)) + adT = hstack((ad1,ad2)) + return adT + + +def ScrewToAxis(q,s_hat,h): + ''' + Takes a point q (3-vector) on the screw, a unit axis s_hat (3-vector) in the direction of the screw, + and a screw pitch h (scalar), and returns the corresponding 6-vector screw axis S (a normalized + spatial velocity). + Example: + + q = [3,0,0] + s_hat = [0,0,1] + h = 2 + ScrewToAxis(q,s_hat,h) + >> array([[ 0], + [ 0], + [ 1], + [ 0], + [-3], + [ 2]]) + ''' + q = asarray(q) + s_hat = asarray(s_hat) + assert len(q) == len(s_hat) == 3, "q or s_hat not a 3-vector" + assert abs(linalg.norm(s_hat) - 1) < 0.001, "s_hat not a valid unit vector" + assert isscalar(h), "h not a scalar" + + q = q.flatten() + s_hat = s_hat.flatten() + + v_wnorm = -cross(s_hat, q) + h*s_hat + v_wnorm.shape = (3,1) + w_unit = s_hat + w_unit.shape = (3,1) + S = vstack((w_unit,v_wnorm)) + return S + + +def AxisAng6(STheta): + ''' + Takes a 6-vector of exp coords STheta and returns the screw axis S and the distance traveled along/ + about the screw axis theta. + Example: + + STheta = [0,0,1,0,-3,2] + S, theta = AxisAng6(STheta) + S + >> array([[ 0.], + [ 0.], + [ 1.], + [ 0.], + [-3.], + [ 2.]]) + theta + >> 1.0 + ''' + STheta = asarray(STheta) + assert len(STheta) == 6, 'Input not a 6-vector' + + w = STheta[:3] + v = STheta[3:] + + if linalg.norm(w) == 0: + theta = linalg.norm(v) + v_unit = normalize(v) + v_unit.shape = (3,1) + S = vstack((zeros((3,1)), v_unit)) + return S, theta + + theta = linalg.norm(w) + w_unit = normalize(w) + w_unit.shape = (3,1) + v_unit = v/theta + v_unit.shape = (3,1) + S = vstack((w_unit,v_unit)) + return S, theta + + +def MatrixExp6(STheta): + ''' + Takes a 6-vector of exp coords STheta and returns the corresponding 4x4 transformation matrix T. + Example: + + STheta = [0,0,1,0,-3,2] + MatrixExp6(STheta) + >> array([[ 0.54030231, -0.84147098, 0. , 1.37909308], + [ 0.84147098, 0.54030231, 0. , -2.52441295], + [ 0. , 0. , 1. , 2. ], + [ 0. , 0. , 0. , 1. ]]) + ''' + STheta = asarray(STheta) + assert len(STheta) == 6, 'Input not a 6-vector' + + S, theta = AxisAng6(STheta) + + w_unit = S[:3] + v_unit = S[3:] + + vTheta = STheta[3:] + vTheta.shape = (3,1) + + if linalg.norm(w_unit) == 0: + R = identity(3) + p = vTheta + T = RpToTrans(R,p) + return T + + r = w_unit*theta + R = MatrixExp3(r) + w_so3mat = VecToso3(w_unit) + p = dot((identity(3)*theta+(1-math.cos(theta))*w_so3mat+(theta-math.sin(theta))*dot(w_so3mat,w_so3mat)), v_unit) + T = RpToTrans(R,p) + return T + + +def MatrixLog6(T): + ''' + Takes a transformation matrix T and returns the corresponding 6-vector of exp coords STheta. + Example: + + T = [[ 0.54030231, -0.84147098, 0. , 1.37909308], + [ 0.84147098, 0.54030231, 0. , -2.52441295], + [ 0. , 0. , 1. , 2. ], + [ 0. , 0. , 0. , 1. ]] + MatrixLog6(T): + >> array([[ 0.00000000e+00], + [ 0.00000000e+00], + [ 9.99999995e-01], + [ 1.12156694e-08], + [ -2.99999999e+00], + [ 2.00000000e+00]]) + ''' + T = asarray(T) + assert T.shape == (4,4), "Input not a 4x4 matrix" + + R, p = TransToRp(T) + + if is_identity_matrix(R): + w_unit = zeros((3,1)) + vTheta = p + STheta = vstack((w_unit, p)) + return STheta + + if trace(R) > -1.001 and trace(R) < -0.999: + theta = math.pi + wTheta = MatrixLog3(R) + w_unit = wTheta/theta + w_so3mat = VecToso3(w_unit) + Ginv = identity(3)/theta - w_so3mat/2 + (1/theta - 1/(math.tan(theta/2)*2))*dot(w_so3mat,w_so3mat) + v_unit = dot(Ginv, p) + vTheta = v_unit*theta + STheta = vstack((wTheta, vTheta)) + return STheta + + theta = math.acos((trace(R)-1)/2) + w_so3mat = (R - R.T)/(2*math.sin(theta)) + Ginv = identity(3)/theta - w_so3mat/2 + (1/theta - 1/(math.tan(theta/2)*2))*dot(w_so3mat,w_so3mat) + wTheta = MatrixLog3(R) + v_unit = dot(Ginv, p) + vTheta = v_unit*theta + STheta = vstack((wTheta, vTheta)) + return STheta + + +def FKinFixed(M,Slist,thetalist): + ''' + Takes + - an element of SE(3): M representing the configuration of the end-effector frame when + the manipulator is at its home position (all joint thetas = 0), + - a list of screw axes Slist for the joints w.r.t fixed world frame, + - a list of joint coords thetalist, + and returns the T of end-effector frame w.r.t. fixed world frame when the joints are at + the thetas specified. + Example: + + S1 = [0,0,1,4,0,0] + S2 = [0,0,0,0,1,0] + S3 = [0,0,-1,-6,0,-0.1] + Slist = [S1, S2, S3] + thetalist = [math.pi/2, 3, math.pi] + M = [[-1, 0, 0, 0], + [ 0, 1, 0, 6], + [ 0, 0, -1, 2], + [ 0, 0, 0, 1]] + FKinFixed(M,Slist,thetalist) + >> array([[ -1.14423775e-17, 1.00000000e+00, 0.00000000e+00, -5.00000000e+00], + [ 1.00000000e+00, 1.14423775e-17, 0.00000000e+00, 4.00000000e+00], + [ 0.00000000e+00, 0.00000000e+00, -1.00000000e+00, 1.68584073e+00], + [ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.00000000e+00]]) + ''' + M = asarray(M) + R_M = TransToRp(M)[0] + assert M.shape == (4,4), "M not a 4x4 matrix" + assert len(Slist[0]) == 6, "Incorrect Screw Axis length" + Slist = asarray(Slist).T + + c = MatrixExp6(Slist[:,0]*thetalist[0]) + for i in range(len(thetalist)-1): + nex = MatrixExp6(Slist[:,i+1]*thetalist[i+1]) + c = dot(c, nex) + + T_se = dot(c, M) + return T_se + + +def FKinBody(M,Blist,thetalist): + ''' + Same as FKinFixed, except here the screw axes are expressed in the end-effector frame. + Example: + + B1 = [0,0,-1,2,0,0] + B2 = [0,0,0,0,1,0] + B3 = [0,0,1,0,0,0.1] + Blist = [S1b, S2b, S3b] + thetalist = [math.pi/2, 3, math.pi] + M = [[-1, 0, 0, 0], + [ 0, 1, 0, 6], + [ 0, 0, -1, 2], + [ 0, 0, 0, 1]] + FKinBody(M,Blist,thetalist) + >> array([[ -1.14423775e-17, 1.00000000e+00, 0.00000000e+00, -5.00000000e+00], + [ 1.00000000e+00, 1.14423775e-17, 0.00000000e+00, 4.00000000e+00], + [ 0.00000000e+00, 0.00000000e+00, -1.00000000e+00, 1.68584073e+00], + [ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.00000000e+00]]) + ''' + M = asarray(M) + R_M = TransToRp(M)[0] + assert M.shape == (4,4), "M not a 4x4 matrix" + assert len(Blist[0]) == 6, "Incorrect Screw Axis length" + Blist = asarray(Blist).T + + c = dot(M, MatrixExp6(Blist[:,0]*thetalist[0])) + for i in range(len(thetalist)-1): + nex = MatrixExp6(Blist[:,i+1]*thetalist[i+1]) + c = dot(c, nex) + + T_se = c + return T_se + + +### end of HW2 functions ############################# + +### start of HW3 functions ########################### + + +def FixedJacobian(Slist,thetalist): + ''' + Takes a list of joint angles (thetalist) and a list of screw axes (Slist) expressed in + fixed space frame, and returns the space Jacobian (a 6xN matrix, where N is the # joints). + Example: + + S1 = [0,0,1,4,0,0] + S2 = [0,0,0,0,1,0] + S3 = [0,0,-1,-6,0,-0.1] + Slist = [S1, S2, S3] + thetalist = [math.pi/2, 3, math.pi] + FixedJacobian(Slist,thetalist) + >> array([[ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00], + [ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00], + [ 1.00000000e+00, 0.00000000e+00, -1.00000000e+00], + [ 4.00000000e+00, -1.00000000e+00, -4.00000000e+00], + [ 0.00000000e+00, 1.11022302e-16, -5.00000000e+00], + [ 0.00000000e+00, 0.00000000e+00, -1.00000000e-01]]) + ''' + N = len(thetalist) + J = zeros((6,N)) + Slist = asarray(Slist).T + + J[:,0] = Slist[:,0] + for k in range(1,N): + c = MatrixExp6(Slist[:,0]*thetalist[0]) + for i in range(k-1): + nex = MatrixExp6(Slist[:,i+1]*thetalist[i+1]) + c = dot(c, nex) + J[:,k] = dot(Adjoint(c), Slist[:,k]) + + return J + + +def BodyJacobian(Blist,thetalist): + ''' + Takes a list of joint angles (thetalist) and a list of screw axes (Blist) expressed in + end-effector body frame, and returns the body Jacobian (a 6xN matrix, where N is the # joints). + Example: + + B1 = [0,0,-1,2,0,0] + B2 = [0,0,0,0,1,0] + B3 = [0,0,1,0,0,0.1] + Blist = [B1, B2, B3] + thetalist = [math.pi/2, 3, math.pi] + BodyJacobian(Blist,thetalist) + >> array([[ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00], + [ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00], + [ -1.00000000e+00, 0.00000000e+00, 1.00000000e+00], + [ -5.00000000e+00, 1.22464680e-16, 0.00000000e+00], + [ -6.12323400e-16, -1.00000000e+00, 0.00000000e+00], + [ 0.00000000e+00, 0.00000000e+00, 1.00000000e-01]]) + ''' + N = len(thetalist) + J = zeros((6,N)) + Blist = asarray(Blist).T + + J[:,N-1] = Blist[:,N-1] + for k in range(N-1): + c = MatrixExp6(-Blist[:,k+1]*thetalist[k+1]) + for i in range(k+2, len(thetalist)): + nex = MatrixExp6(-Blist[:,i]*thetalist[i]) + c = dot(nex, c) + J[:,k] = dot(Adjoint(c), Blist[:,k]) + + return J + + +def IKinBody(Blist, M, T_sd, thetalist_init, wthresh, vthresh): + ''' + A numerical inverse kinematics routine based on Newton-Raphson method. + Takes a list of screw axes (Blist) expressed in end-effector body frame, the end-effector zero + configuration (M), the desired end-effector configuration (T_sd), an initial guess of joint angles + (thetalist_init), and small positive scalar thresholds (wthresh, vthresh) controlling how close the + final solution thetas must be to the desired thetas. + Example: + + wthresh = 0.01 + vthresh = 0.001 + M = [[1,0,0,-.817],[0,0,-1,-.191],[0,1,0,-.006],[0,0,0,1]] + T_sd = [[0,1,0,-.6],[0,0,-1,.1],[-1,0,0,.1],[0,0,0,1]] + thetalist_init = [0]*6 + B1 = [0,1,0,.191,0,.817] + B2 = [0,0,1,.095,-.817,0] + B3 = [0,0,1,.095,-.392,0] + B4 = [0,0,1,.095,0,0] + B5 = [0,-1,0,-.082,0,0] + B6 = [0,0,1,0,0,0] + Blist = [B1,B2,B3,B4,B5,B6] + round(IKinBody(Blist, M, T_sd, thetalist_init, wthresh, vthresh), 3) + >> + array([[ 0. , 0. , 0. , 0. , 0. , 0. ], + [-0.356, -0.535, 0.468, 1.393, -0.356, -2.897], + [-0.399, -1.005, 1.676, -0.434, -0.1 , -1.801], + [-0.516, -1.062, 1.731, -1.63 , -0.502, -0.607], + [-0.493, -0.923, 1.508, -0.73 , -0.289, -1.42 ], + [-0.472, -0.818, 1.365, -0.455, -0.467, -1.662], + [-0.469, -0.834, 1.395, -0.561, -0.467, -1.571]]) + ''' + T_sd = asarray(T_sd) + assert T_sd.shape == (4,4), "T_sd not a 4x4 matrix" + + maxiterates = 100 + N = len(thetalist_init) + + jointAngles = asarray(thetalist_init).reshape(1,N) + + T_sb = FKinBody(M, Blist, thetalist_init) + Vb = MatrixLog6(dot(TransInv(T_sb), T_sd)) + wb = Vb[:3, 0] + vb = Vb[3:, 0] + + thetalist_i = asarray(thetalist_init) + + i = 0 + + while i<maxiterates and (linalg.norm(wb)>wthresh or linalg.norm(vb)>vthresh): + thetalist_next = thetalist_i.reshape(N,1) + dot(linalg.pinv(BodyJacobian(Blist,thetalist_i)), Vb) + # thetalist_next = (thetalist_next + pi)%(2*pi) - pi + jointAngles = vstack((jointAngles, thetalist_next.reshape(1,N))) + T_sb = FKinBody(M, Blist, thetalist_next.flatten()) + Vb = MatrixLog6(dot(TransInv(T_sb), T_sd)) + thetalist_i = thetalist_next.reshape(N,) + wb = Vb[:3, 0] + vb = Vb[3:, 0] + i += 1 + + return jointAngles + + +def IKinFixed(Slist, M, T_sd, thetalist_init, wthresh, vthresh): + ''' + Similar to IKinBody, except the screw axes are in the fixed space frame. + Example: + + M = [[1,0,0,0],[0,1,0,0],[0,0,1,0.910],[0,0,0,1]] + T_sd = [[1,0,0,.4],[0,1,0,0],[0,0,1,.4],[0,0,0,1]] + thetalist_init = [0]*7 + S1 = [0,0,1,0,0,0] + S2 = [0,1,0,0,0,0] + S3 = [0,0,1,0,0,0] + S4 = [0,1,0,-0.55,0,0.045] + S5 = [0,0,1,0,0,0] + S6 = [0,1,0,-0.85,0,0] + S7 = [0,0,1,0,0,0] + Slist = [S1,S2,S3,S4,S5,S6,S7] + round(IKinFixed(Slist, M, T_sd, thetas, wthresh, vthresh), 3) + >> + array([[ 0. , 0. , 0. , 0. , 0. , 0. , 0. ], + [ 0. , 4.471, -0. , -11.333, -0. , 6.863, -0. ], + [ -0. , 3.153, -0. , -5.462, -0. , 2.309, 0. ], + [ -0. , -1.006, 0. , 5.679, -0. , -4.673, 0. ], + [ -0. , 1.757, 0. , -0.953, 0. , -0.804, -0. ], + [ -0. , 1.754, 0. , -2.27 , -0. , 0.516, -0. ], + [ 0. , 1.27 , 0. , -1.85 , -0. , 0.58 , -0. ], + [ 0. , 1.367, 0. , -1.719, -0. , 0.351, -0. ], + [ 0. , 1.354, 0. , -1.71 , -0. , 0.356, -0. ]]) + ''' + T_sd = asarray(T_sd) + assert T_sd.shape == (4,4), "T_sd not a 4x4 matrix" + + maxiterates = 100 + + N = len(thetalist_init) + + jointAngles = asarray(thetalist_init).reshape(1,N) + + T_sb = FKinFixed(M, Slist, thetalist_init) + Vb = MatrixLog6(dot(TransInv(T_sb), T_sd)) + wb = Vb[:3, 0] + vb = Vb[3:, 0] + + thetalist_i = asarray(thetalist_init) + + i = 0 + + while i<maxiterates and (linalg.norm(wb)>wthresh or linalg.norm(vb)>vthresh): + Jb = dot(Adjoint(TransInv(T_sb)), FixedJacobian(Slist,thetalist_i)) + thetalist_next = thetalist_i.reshape(N,1) + dot(linalg.pinv(Jb), Vb) + jointAngles = vstack((jointAngles, thetalist_next.reshape(1,N))) + + T_sb = FKinFixed(M, Slist, thetalist_next.flatten()) + Vb = MatrixLog6(dot(TransInv(T_sb), T_sd)) + thetalist_i = thetalist_next.reshape(N,) + wb = Vb[:3, 0] + vb = Vb[3:, 0] + i += 1 + + return jointAngles + + +### end of HW3 functions ############################# + +### start of HW4 functions ########################### + + +def CubicTimeScaling(T,t): + ''' + Takes a total travel time T and the current time t satisfying 0 <= t <= T and returns + the path parameter s corresponding to a motion that begins and ends at zero velocity. + Example: + + CubicTimeScaling(10, 7) + >> 0.78399 + ''' + assert t >= 0 and t <= T, 'Invalid t' + + s = (3./(T**2))*(t**2) - (2./(T**3))*(t**3) + return s + + +def QuinticTimeScaling(T,t): + ''' + Takes a total travel time T and the current time t satisfying 0 <= t <= T and returns + the path parameter s corresponding to a motion that begins and ends at zero velocity + and zero acceleration. + Example: + + QuinticTimeScaling(10,7) + >> 0.83692 + ''' + assert t >= 0 and t <= T, 'Invalid t' + + s = (10./(T**3))*(t**3) + (-15./(T**4))*(t**4) + (6./(T**5))*(t**5) + return s + + +def JointTrajectory(thetas_start, thetas_end, T, N, method='cubic'): + ''' + Takes initial joint positions (n-dim) thetas_start, final joint positions thetas_end, the time of + the motion T in seconds, the number of points N >= 2 in the discrete representation of the trajectory, + and the time-scaling method (cubic or quintic) and returns a trajectory as a matrix with N rows, + where each row is an n-vector of joint positions at an instant in time. The trajectory is a straight-line + motion in joint space. + Example: + + thetas_start = [0.1]*6 + thetas_end = [pi/2]*6 + T = 2 + N = 5 + JointTrajectory(thetas_start, thetas_end, T, N, 'cubic') + >> + array([[ 0.1 , 0.1 , 0.1 , 0.1 , 0.1 , 0.1 ], + [ 0.33 , 0.33 , 0.33 , 0.33 , 0.33 , 0.33 ], + [ 0.835, 0.835, 0.835, 0.835, 0.835, 0.835], + [ 1.341, 1.341, 1.341, 1.341, 1.341, 1.341], + [ 1.571, 1.571, 1.571, 1.571, 1.571, 1.571]]) + ''' + assert len(thetas_start) == len(thetas_end), 'Incompatible thetas' + assert N >= 2, 'N must be >= 2' + assert isinstance(N, int), 'N must be an integer' + assert method == 'cubic' or method == 'quintic', 'Incorrect time-scaling method argument' + + trajectory = asarray(thetas_start) + + if method == 'cubic': + for i in range(1,N): + t = i*float(T)/(N-1) + s = CubicTimeScaling(T,t) + thetas_s = asarray(thetas_start)*(1-s) + asarray(thetas_end)*s + trajectory = vstack((trajectory, thetas_s)) + return trajectory + + elif method == 'quintic': + for i in range(1,N): + t = i*float(T)/(N-1) + s = QuinticTimeScaling(T,t) + thetas_s = asarray(thetas_start)*(1-s) + asarray(thetas_end)*s + trajectory = vstack((trajectory, thetas_s)) + return trajectory + + +def ScrewTrajectory(X_start, X_end, T, N, method='cubic'): + ''' + Similar to JointTrajectory, except that it takes the initial end-effector configuration X_start in SE(3), + the final configuration X_end, and returns the trajectory as a 4N x 4 matrix in which every 4 rows is an + element of SE(3) separated in time by T/(N-1). This represents a discretized trajectory of the screw motion + from X_start to X_end. + Example: + + thetas_start = [0.1]*6 + thetas_end = [pi/2]*6 + M_ur5 = [[1,0,0,-.817],[0,0,-1,-.191],[0,1,0,-.006],[0,0,0,1]] + S1_ur5 = [0,0,1,0,0,0] + S2_ur5 = [0,-1,0,.089,0,0] + S3_ur5 = [0,-1,0,.089,0,.425] + S4_ur5 = [0,-1,0,.089,0,.817] + S5_ur5 = [0,0,-1,.109,-.817,0] + S6_ur5 = [0,-1,0,-.006,0,.817] + Slist_ur5 = [S1_ur5,S2_ur5,S3_ur5,S4_ur5,S5_ur5,S6_ur5] + X_start = FKinFixed(M_ur5, Slist_ur5, thetas_start) + X_end = FKinFixed(M_ur5, Slist_ur5, thetas_end) + T = 2 + N = 3 + ScrewTrajectory(X_start, X_end, T, N, 'quintic') + >> + array([[ 0.922, -0.388, 0.004, -0.764], + [-0.007, -0.029, -1. , -0.268], + [ 0.388, 0.921, -0.03 , -0.124], + [ 0. , 0. , 0. , 1. ], + [ 0.534, -0.806, 0.253, -0.275], + [ 0.681, 0.234, -0.694, -0.067], + [ 0.5 , 0.543, 0.674, -0.192], + [ 0. , 0. , 0. , 1. ], + [ 0. , -1. , -0. , 0.109], + [ 1. , 0. , 0. , 0.297], + [-0. , -0. , 1. , -0.254], + [ 0. , 0. , 0. , 1. ]]) + ''' + R_start, p_start = TransToRp(X_start) #Just to ensure X_start is valid + R_end ,p_end = TransToRp(X_end) #Just to ensure X_end is valid + assert N >= 2, 'N must be >= 2' + assert isinstance(N, int), 'N must be an integer' + assert method == 'cubic' or method == 'quintic', 'Incorrect time-scaling method argument' + + trajectory = X_start + + if method == 'cubic': + for i in range(1,N): + t = i*float(T)/(N-1) + s = CubicTimeScaling(T,t) + X_s = X_start.dot(MatrixExp6(MatrixLog6(TransInv(X_start).dot(X_end))*s)) + trajectory = vstack((trajectory, X_s)) + return trajectory + + elif method == 'quintic': + for i in range(1,N): + t = i*float(T)/(N-1) + s = QuinticTimeScaling(T,t) + X_s = X_start.dot(MatrixExp6(MatrixLog6(TransInv(X_start).dot(X_end))*s)) + trajectory = vstack((trajectory, X_s)) + return trajectory + + +def CartesianTrajectory(X_start, X_end, T, N, method='cubic'): + ''' + Similar to ScrewTrajectory, except the origin of the end-effector frame follows a straight line, + decoupled from the rotational motion. + Example: + + thetas_start = [0.1]*6 + thetas_end = [pi/2]*6 + M_ur5 = [[1,0,0,-.817],[0,0,-1,-.191],[0,1,0,-.006],[0,0,0,1]] + S1_ur5 = [0,0,1,0,0,0] + S2_ur5 = [0,-1,0,.089,0,0] + S3_ur5 = [0,-1,0,.089,0,.425] + S4_ur5 = [0,-1,0,.089,0,.817] + S5_ur5 = [0,0,-1,.109,-.817,0] + S6_ur5 = [0,-1,0,-.006,0,.817] + Slist_ur5 = [S1_ur5,S2_ur5,S3_ur5,S4_ur5,S5_ur5,S6_ur5] + X_start = FKinFixed(M_ur5, Slist_ur5, thetas_start) + X_end = FKinFixed(M_ur5, Slist_ur5, thetas_end) + T = 2 + N = 3 + CartesianTrajectory(X_start, X_end, T, N, 'quintic') + >> + array([[ 0.922, -0.388, 0.004, -0.764], + [-0.007, -0.029, -1. , -0.268], + [ 0.388, 0.921, -0.03 , -0.124], + [ 0. , 0. , 0. , 1. ], + [ 0.534, -0.806, 0.253, -0.327], + [ 0.681, 0.234, -0.694, 0.014], + [ 0.5 , 0.543, 0.674, -0.189], + [ 0. , 0. , 0. , 1. ], + [ 0. , -1. , -0. , 0.109], + [ 1. , 0. , 0. , 0.297], + [-0. , -0. , 1. , -0.254], + [ 0. , 0. , 0. , 1. ]]) + + Notice the R of every T is same for ScrewTrajectory and CartesianTrajectory, but the translations + are different. + ''' + R_start, p_start = TransToRp(X_start) + R_end ,p_end = TransToRp(X_end) + assert N >= 2, 'N must be >= 2' + assert isinstance(N, int), 'N must be an integer' + assert method == 'cubic' or method == 'quintic', 'Incorrect time-scaling method argument' + + trajectory = X_start + + if method == 'cubic': + for i in range(1,N): + t = i*float(T)/(N-1) + s = CubicTimeScaling(T,t) + p_s = (1-s)*p_start + s*p_end + R_s = R_start.dot(MatrixExp3(MatrixLog3(RotInv(R_start).dot(R_end))*s)) + X_s = RpToTrans(R_s, p_s) + trajectory = vstack((trajectory, X_s)) + return trajectory + + elif method == 'quintic': + for i in range(1,N): + t = i*float(T)/(N-1) + s = QuinticTimeScaling(T,t) + p_s = (1-s)*p_start + s*p_end + R_s = R_start.dot(MatrixExp3(MatrixLog3(RotInv(R_start).dot(R_end))*s)) + X_s = RpToTrans(R_s, p_s) + trajectory = vstack((trajectory, X_s)) + return trajectory + + +### end of HW4 functions ############################# + +### start of HW5 functions ########################### + + +def LieBracket(V1, V2): + assert len(V1)==len(V2)==6, 'Needs two 6 vectors' + V1.shape = (6,1) + w1 = V1[:3,:] + v1 = V1[3:,:] + + w1_mat = VecToso3(w1) + v1_mat = VecToso3(v1) + col1 = vstack((w1_mat, v1_mat)) + col2 = vstack((zeros((3,3)), w1_mat)) + mat1 = hstack((col1, col2)) + + return mat1.dot(V2) + + +def TruthBracket(V1, V2): # Transposed version of Lie Bracket + assert len(V1)==len(V2)==6, 'Needs two 6 vectors' + V1.shape = (6,1) + w1 = V1[:3,:] + v1 = V1[3:,:] + + w1_mat = VecToso3(w1) + v1_mat = VecToso3(v1) + col1 = vstack((w1_mat, v1_mat)) + col2 = vstack((zeros((3,3)), w1_mat)) + mat1 = hstack((col1, col2)) + + return (mat1.T).dot(V2) + + +def InverseDynamics(thetas, thetadots, thetadotdots, g, Ftip, M_rels, Glist, Slist): + ''' + M1 = array(([1.,0.,0.,0.],[0.,1.,0.,0.],[0.,0.,1.,0.],[0.,0.,.089159,1.])).T + M2 = array(([0.,0.,-1.,0.],[0.,1.,0.,0.],[1.,0.,0.,0.],[.28,.13585,.089159,1.])).T + M3 = array(([0.,0.,-1.,0.],[0.,1.,0.,0.],[1.,0.,0.,0.],[.675,.01615,.089159,1.])).T + M4 = array(([-1.,0.,0.,0.],[0.,1.,0.,0.],[0.,0.,-1.,0.],[.81725,.01615,.089159,1.])).T + M5 = array(([-1.,0.,0.,0.],[0.,1.,0.,0.],[0.,0.,-1.,0.],[.81725,.10915,.089159,1.])).T + M6 = array(([-1.,0.,0.,0.],[0.,1.,0.,0.],[0.,0.,-1.,0.],[.81725,.10915,-.005491,1.])).T + M01 = array(([1.,0.,0.,0.],[0.,1.,0.,0.],[0.,0.,1.,0.],[0.,0.,.089159,1.])).T + M12 = array(([0.,0.,-1.,0.],[0.,1.,0.,0.],[1.,0.,0.,0.],[.28,.13585,0.,1.])).T + M23 = array(([1.,0.,0.,0.],[0.,1.,0.,0.],[0.,0.,1.,0.],[0.,-.1197,.395,1])).T + M34 = array(([0.,0.,-1.,0.],[0.,1.,0.,0.],[1.,0.,0.,0.],[0.,0.,.14225,1.])).T + M45 = array(([1.,0.,0.,0.],[0.,1.,0.,0.],[0.,0.,1.,0.],[0.,.093,0.,1.])).T + M56 = array(([1.,0.,0.,0.],[0.,1.,0.,0.],[0.,0.,1.,0.],[0.,0.,.09465,1.])).T + + G1 = array(([.010267,0.,0.,0.,0.,0.],[0.,.010267,0.,0.,0.,0.],[0.,0.,.00666,0.,0.,0.],[0.,0.,0.,3.7,0.,0.],[0.,0.,0.,0.,3.7,0.],[0.,0.,0.,0.,0.,3.7])) + G2 = array(([.22689,0.,0.,0.,0.,0.],[0.,.22689,0.,0.,0.,0.],[0.,0.,.0151074,0.,0.,0.],[0.,0.,0.,8.393,0.,0.],[0.,0.,0.,0.,8.393,0.],[0.,0.,0.,0.,0.,8.393])) + G3 = array(([.0494433,0.,0.,0.,0.,0.],[0.,.0494433,0.,0.,0.,0.],[0.,0.,.004095,0.,0.,0.],[0.,0.,0.,2.275,0.,0.],[0.,0.,0.,0.,2.275,0.],[0.,0.,0.,0.,0.,2.275])) + G4 = array(([.111172,0.,0.,0.,0.,0.],[0.,.111172,0.,0.,0.,0.],[0.,0.,.21942,0.,0.,0.],[0.,0.,0.,1.219,0.,0.],[0.,0.,0.,0.,1.219,0.],[0.,0.,0.,0.,0.,1.219])) + G5 = array(([.111172,0.,0.,0.,0.,0.],[0.,.111172,0.,0.,0.,0.],[0.,0.,.21942,0.,0.,0.],[0.,0.,0.,1.219,0.,0.],[0.,0.,0.,0.,1.219,0.],[0.,0.,0.,0.,0.,1.219])) + G6 = array(([.0171364,0.,0.,0.,0.,0.],[0.,.0171364,0.,0.,0.,0.],[0.,0.,.033822,.0,0.,0.],[0.,0.,0.,.1879,0.,0.],[0.,0.,0.,0.,.1879,0.],[0.,0.,0.,0.,0.,.1879])) + + Slist = [[0.,0.,1.,0.,0.,0.],[0.,1.,0.,-.089,0.,0.],[0.,1.,0.,-.089,0.,.425],[0.,1.,0.,-.089,0.,.817],[0.,0.,-1.,-.109,.817,.0],[0.,1.,0.,.006,0.,.817]] + + Glist = [G1,G2,G3,G4,G5,G6] + M_rels = [M01,M12,M23,M34,M45,M56] + Ftip = [0.,0.,0.,0.,0.,0.] + ''' + assert len(thetas) == len(thetadots) == len(thetadotdots), 'Joint inputs mismatch' + Slist = asarray(Slist) + N = len(thetas) # no. of links + Ftip = asarray(Ftip) + + # initialize iterables + Mlist = [0]*N + T_rels = [0]*N + Vlist = [0]*N + Vdotlist = [0]*N + Alist = [0]*N + Flist = [0]*N + Taulist = [0]*N + + + Mlist[0] = M_rels[0] + for i in range(1, N): + Mlist[i] = Mlist[i-1].dot(M_rels[i]) + + + for i in range(N): + Alist[i] = Adjoint(TransInv(Mlist[i])).dot(Slist[i]) + + + for i in range(N): + T_rels[i] = M_rels[i].dot(MatrixExp6(Alist[i]*thetas[i])) + + + V0 = zeros((6,1)) + Vlist[0] = V0 + + Vdot0 = -asarray([0,0,0]+g) + Vdotlist[0] = Vdot0 + + F_ip1 = asarray(Ftip).reshape(6,1) + + # forward iterations + for i in range(1, N): + # print i + T_i_im1 = TransInv(T_rels[i]) #### should it be i-1??? + + Vlist[i] = Adjoint(T_i_im1).dot(Vlist[i-1]) + (Alist[i]*thetadots[i]).reshape(6,1) + + Vdotlist[i] = Adjoint(T_i_im1).dot(Vdotlist[i-1]) + LieBracket(Vlist[i], Alist[i])*thetadots[i] + Alist[i]*thetadotdots[i] + + + # print T_rels + # print Vlist + # print Vdotlist + # print Alist + + # backward iterations + for i in range(N-1,-1,-1): + T_ip1_i = TransInv(T_rels[i]) + Flist[i] = (Adjoint(T_ip1_i).T).dot(F_ip1) + (Glist[i].dot(Vdotlist[i])).reshape(6,1) - TruthBracket(Vlist[i], Glist[i].dot(Vlist[i])) + Taulist[i] = (Flist[i].T).dot(Alist[i]) + + return asarray(Taulist).flatten() + + +def InertiaMatrix(thetas, M_rels, Glist, Slist): + Slist = asarray(Slist) + N = len(thetas) # no. of links + + M = zeros((N,N)) + + for i in range(N): + thetadotdots = [0]*N + thetadotdots[i] = 1 + M[:, i] = InverseDynamics(thetas, [0]*6, thetadotdots, [0]*3, [0]*6, M_rels, Glist, Slist) + + return M + + +def CoriolisForces(thetas, thetadots, M_rels, Glist, Slist): + C = InverseDynamics(thetas, thetadots, [0]*6, [0]*3, [0]*6, M_rels, Glist, Slist) + return C + + +def GravityForces(thetas, g, M_rels, Glist, Slist): + Gvec = InverseDynamics(thetas, [0]*6, [0]*6, g, [0]*6, M_rels, Glist, Slist) + return Gvec + + +def EndEffectorForces(Ftip, thetas, M_rels, Glist, Slist): + return InverseDynamics(thetas, [0]*6, [0]*6, [0]*3, Ftip, M_rels, Glist, Slist) + + +def ForwardDynamics(thetas, thetadots, taus, g, Ftip, M_rels, Glist, Slist): + M = InertiaMatrix(thetas, M_rels, Glist, Slist) + C = CoriolisForces(thetas, thetadots, M_rels, Glist, Slist) + Gvec = GravityForces(thetas, g, M_rels, Glist, Slist) + eeF = EndEffectorForces(Ftip, thetas, M_rels, Glist, Slist) + + thetadotdots = (linalg.pinv(M)).dot(taus - C - Gvec - eeF) + return thetadotdots + + +def EulerStep(thetas_t, thetadots_t, thetadotdots_t, delt): + thetas_t = asarray(thetas_t) + thetadots_t = asarray(thetadots_t) + thetadotdots_t = asarray(thetadotdots_t) + + thetas_next = thetas_t + delt*thetadots_t + thetadots_next = thetadots_t + delt*thetadotdots_t + + return thetas_next, thetadots_next + + +def InverseDynamicsTrajectory(thetas_traj, thetadots_traj, thetadotdots_traj, Ftip_traj, g, M_rels, Glist, Slist): + Np1 = len(thetas_traj) + # N = Np1-1 + idtraj = [] + for i in range(Np1): + taus = InverseDynamics(thetas_traj[i], thetadots_traj[i], thetadotdots_traj[i], g, Ftip_traj[i], M_rels, Glist, Slist) + idtraj.append(taus) + + return asarray(idtraj) + + +def ForwardDynamicsTrajectory(thetas_init, thetadots_init, tau_hist, delt, g, Ftip_traj, M_rels, Glist, Slist): + Np1 = len(tau_hist) + thetas_traj = asarray(thetas_init) + thetadots_traj = asarray(thetadots_init) + + for i in range(Np1): + thetadotdots_init = ForwardDynamics(thetas_init, thetadots_init, tau_hist[i], g, Ftip_traj[i], M_rels, Glist, Slist) + thetas_next, thetadots_next = EulerStep(thetas_init, thetadots_init, thetadotdots_init, delt) + # append new state + thetas_traj = hstack((thetas_traj, thetas_next)) + thetadots_traj = hstack((thetadots_traj, thetadots_next)) + # update initial conditions + thetas_init = thetas_next + thetadots_init = thetadots_next + + return thetas_traj.reshape(Np1+1, len(thetas_init)), thetadots_traj.reshape(Np1+1, len(thetas_init)) + + +### end of HW5 functions ############################# \ No newline at end of file