Ejemplo n.º 1
0
def generate_symmetric_curve(t=None,
                             x_func=n.cos,
                             y_func=n.sin,
                             curve_factor=2 * n.pi,
                             freq=1,
                             ampl_factor=0.1,
                             num_points=50,
                             offset=0):
    """
    Genrates a Homogenous point-curve with z=0 in the following matrix form:
    [[x1, y1, 0, 1},
         .....     ,
     [xn, yn, 0, 1}]
     in local (unransformed) plane-coordinates in metres.

    parameters:
                curve_factor : ...
                freq         : ...
                ampl_factor  : 'diameter' of the curve
                num_points   : ...
    """
    if t is None:
        t = n.linspace(0, 1, num_points)

    le = len(t)
    y = y_func(t / t[-1] * curve_factor * freq)
    y = y / n.max(n.abs(y))

    x = x_func(t / t[-1] * curve_factor * freq)
    x = x / n.max(n.abs(x))

    ampl_factor = ampl_factor / 2.0
    point_matrix = mat(
        zip(x * ampl_factor, y * ampl_factor, n.zeros(le), n.ones(le)))
    return point_matrix
Ejemplo n.º 2
0
def generate_curve(xmin=-0.25,
                   xmax=0.25,
                   x_func=None,
                   y_func=n.sin,
                   curve_factor=n.pi,
                   freq=1,
                   ampl_factor=0.25,
                   num_points=50,
                   offset=0):
    """
    Genrates a Homogenous point-curve with z=0 in the following matrix form:
    [[x1, y1, 0, 1},
         .....     ,
     [xn, yn, 0, 1}]
     in local (unransformed) plane-coordinates in metres.
    """
    if x_func is None:
        if xmin > xmax:
            xmin, xmax = xmax, xmin
        x_func = n.linspace(xmin, xmax, num_points)

    le = len(x_func)
    y = y_func(x_func / n.abs(xmax) * curve_factor * freq)

    if n.max(n.abs(y)) > 0:
        y = y / n.max(n.abs(y))

    point_matrix = mat(
        zip(x_func + offset, y * ampl_factor, n.zeros(le), n.ones(le)))
    return point_matrix
def filter_solutions(solutions, filter_function = check_solution):
    result = []
    for s in solutions.T:
        if filter_function(*s) == True:
            result.append( s )
    # returns non-flipped, flipped
    return mat(zip(*result))
def find_single_path(ik_curve):
    result = ik_curve
    total = []
    with utils.timing.Timer() as t:
        for index in xrange(len(result[0])):
            path = __find_path(result, index)
            if path:
                return mat(path)
    def test_forward_kinematics_general(self):
        print '\ntest_forward_kinematics_general'

        for counter in xrange(10000):
            fcounter = (counter / 10000.0)*100
            if fcounter % 1.0 == 0.0:
                print fcounter
            j1 = rand_range(-180, 180)
            j2 = rand_range(-90, 110)
            j3 = rand_range(-230, 50)
            j4 = rand_range(-200, 200)
            j5 = rand_range(-115, 115)
            j6 = rand_range(-400, 400)

            # makes sure we never end up at a singular point

            while (abs(j3) - 90) < 1e-7:
                j3 = rand_range(-230, 50)

            s0 = j1,j2,j3,j4,j5,j6
            robot_info = forward_kinematics(j1, j2, j3, j4, j5, j6, **DH_TABLE)
            T44, debug1 = robot_info['flange'], robot_info['robot_geometry_local']

            while norm(calc_wcp(T44,L=0.065)[:2]) < 1e-7:
                j2 = rand_range(-90, 110)
                T44, debug1  = forward_kinematics(j1, j2, j3, j4, j5, j6, **DH_TABLE)

            sol = mat( inverse_kinematics_irb140(DH_TABLE, T44) )
            num_valid_solutions = 0
            for s in sol.T:
                robot_info = forward_kinematics(*s, **DH_TABLE)
                A, debug2  = robot_info['flange'], robot_info['robot_geometry_local']
                num_valid_solutions += check_solution(*s)
                error = norm(A - T44)
                if not n.isnan(error):
                    self.assertAlmostEqual(error, 0)
            self.assertGreaterEqual(num_valid_solutions, 1)
            self.assertEqual(num_valid_solutions, calc_valid_raw_invkin_irb140(T44).shape[0])

            L = []
            for s in iterdim(sol,1):
                if check_solution(*s) == True:
                    L.append(s)
            L = mat(L)
            self.assertTrue(norm(calc_valid_raw_invkin_irb140(T44) - L) == 0.0)
def plot_robot_geometry(robot_info, color='k'):
    global_robot_frames = mat(robot_info['robot_geometry_global'])
    plot(global_robot_frames[:, 0, 3],
         global_robot_frames[:, 2, 3],
         color,
         linewidth=2)

    tool_pos = nzip(robot_info['tcp'][:3, 3], robot_info['flange'][:3, 3]).T
    plot(tool_pos[:, 0], tool_pos[:, 2], color='g', linewidth=3)
def find_paths(ik_curve):
    result = ik_curve
    total = []
    with utils.timing.Timer() as t:
        for index in xrange(len(result[0])):
            path = __find_path(result, index)
            if path:
                print 'FOUND ONE'
                total.append(list(path))
        return mat(total)
def __inverse_kinematics_pose(T44, filtering=False, raw_solutions=False):
    # perform inverse kinematics on a single frame
    angle_solutions = inverse_kinematics_irb140(DH_TABLE, T44)
    if not raw_solutions:
        extra = [angle_solutions]
        for index in xrange(6):
            extra.append( generate_modulo_solutions(angle_solutions, index, 360.0))
            extra.append( generate_modulo_solutions(angle_solutions, index, -360.0))
            pass
        angle_solutions = merge_solutions(*extra)
    if filtering:
        angle_solutions = filter_solutions(angle_solutions)
    return mat(angle_solutions.T)
def inverse_kinematics_irb140(dh_table, T44):
    '''
    Wrapper function that calculates the 20 analytical solutions
    to the IRB140 robot.
    '''
    if type(T44) is list:
        T44 = mat(T44)
    dim = T44.shape
    if len(dim) != 2:
        raise ArithmeticError('Forward-kinematics must be a 4x4 matrix!')
    if dim[0] != dim[1]:
        raise ArithmeticError('Forward-kinematics must be square!')
    if dim[0] != 4:
        raise ArithmeticError('Forward-kinematics must have dimension of 4!')

    if not dh_table.has_key('tool'):
        dh_table['tool'] = None

    tool = dh_table['tool']

    if not (tool is None):
        T44 = T44.dot( inv(tool) )
    # x5 for each elb_x
    sol_elbup      = inverse_kinematics_elbow_up(dh_table, T44)
    sol_elbdown    = inverse_kinematics_elbow_down(dh_table, T44)
    sol_elbup_backward   = inverse_kinematics_elbow_up(dh_table, T44, flipped = True)
    sol_elbdown_backward = inverse_kinematics_elbow_down(dh_table, T44, flipped = True)

    #first columnt is first solution and so forth
##    ret = mat(zip(sol_elbup1, sol_elbdown1, sol_elbup1_fl, sol_elbdown1_fl,
##                  sol_elbup2, sol_elbdown2, sol_elbup2_fl, sol_elbdown2_fl,
##                  sol_elbup3, sol_elbdown3, sol_elbup3_fl, sol_elbdown3_fl))

    #first columnt is first solution and so forth
    ret = mat( zip( sol_elbup, sol_elbdown, sol_elbup_backward, sol_elbdown_backward ) )
    k,m,n = ret.shape
    ret = ret.reshape(k*m,n)
    return ret.T
Ejemplo n.º 10
0
def define_plane_from_directions(origin, dirx, diry, system_type='local'):
    """
        This function returns a coordinate system frame (NxN matrix),
        for a plane defined by a matrix containing a point of origin (t)
        and a set of basis vectors (R) all of dimension N: [[R, t,]
                                                            [0, 1]]
    """
    if not system_type in ['local', 'global']:
        raise ArithmeticError(
            'Only local or global coordinate system descriptions allowed')
    origin, dirx, diry = convert_to_mat(origin, dirx, diry)
    diry = gram_schmith_step(diry, dirx)
    diry = diry / norm(diry)
    dirx = dirx / norm(dirx)
    normal = mat([rand(), rand(), rand()])
    normal = gram_schmith_step(normal, dirx)
    normal = gram_schmith_step(normal, diry)

    plane_transform = expand_matrix(mat([dirx, diry, normal, origin]).T, 1, 0)
    if system_type == 'global':
        return mat_flip(plane_transform)
    else:
        return plane_transform
Ejemplo n.º 11
0
def transform_to_next(A, alpha, D, theta, convention='standard'):
    """
    Calculats transform from frame J = I-1 to I
    in order AI = Rzj( theta )Tzj( D )Txi( A )Rxi( alpha )
    and parameters are given in order A, alpha, D, theta, 
    according to  the standard convention:

            matrix =   mat([[ct,    -st*ca,  st*sa, A*ct],
                            [st,     ct*ca, -ct*sa, A*st],
                            [ 0,        sa,     ca,   D ],
                            [ 0,         0,      0,   1 ]]);

    If convention is changed to modified then the transformation
    is remapped according to the equivalent modified Denivit-hartenberg,
    and performs the mapping from I to I+1.
    """
    Rz_J = homogenous_rotation_z(theta)
    Tz_J = homogenous_translation_z(D)
    Tx_I = homogenous_translation_x(A)
    Rx_I = homogenous_rotation_x(alpha)
    matrix = matmul(Rz_J, Tz_J, Tx_I, Rx_I)

    if convention.lower() == 'standard':
        return matrix
    elif convention.lower() == 'modified':
        modified = mat([
            matrix[0, 0],
            -matrix[1, 0],
            matrix[2, 0],
            A,
            -matrix[0, 1],
            matrix[1, 1],
            -matrix[2, 1],
            -matrix[2, 1] * D,
            matrix[0, 2],
            -matrix[1, 2],
            matrix[2, 2],
            matrix[2, 2] * D,
            0,
            0,
            0,
            1,
        ]).reshape((4, 4))
        return modified
    else:
        raise ArithmeticError(
            "As of writing this function only two conventions are allowed: 'standard' or 'modified'."
        )
    def test_elbow_up_backward_facing(self):
        print '\ntest_elbow_up_backward'
        for _ in xrange(100):
            j1 =  rand_range(-180, 180)
            j2 = -40
            j3 = -100
            j4 = rand_range(-200, 200)
            j5 = rand_range(-115, 115)
            j6 = rand_range(-400, 400)

            robot_info = forward_kinematics(j1,j2,j3,j4,j5,j6,**DH_TABLE)
            A, debug = robot_info['flange'], robot_info['robot_geometry_local']

            sol = mat([j1,j2,j3,j4,j5,j6])
            s = inverse_kinematics_elbow_up(DH_TABLE, A, flipped = True)
            self.assertNotEqual(n.isnan(n.sum(s)), True)
            a,b,c = s[0][0:3]
            self.assertAlmostEqual(a, j1)
            self.assertAlmostEqual(b, j2)
            self.assertAlmostEqual(c, j3)
            a,b,c = s[1][0:3]
            self.assertAlmostEqual(a, j1)
            self.assertAlmostEqual(b, j2)
            self.assertAlmostEqual(c, j3)

            s = inverse_kinematics_elbow_down(DH_TABLE, A, flipped = True)
            a,b,c = s[0][0:3]
            self.assertAlmostEqual(a, j1)
            self.assertNotAlmostEqual(b, j2)
            self.assertNotAlmostEqual(c, j3)
            a,b,c = s[1][0:3]
            self.assertAlmostEqual(a, j1)
            self.assertNotAlmostEqual(b, j2)
            self.assertNotAlmostEqual(c, j3)

            # check if they are stored in the right order i.e.
            # elbow_up, elbow_down, elbow_up_backward, delbow_down_backward
            sols = inverse_kinematics_irb140(DH_TABLE, A)
            for i in xrange(2, len(sols.T), 4):
                a,b,c = sols[:,i][:3]
                self.assertAlmostEqual(a, j1)
                self.assertAlmostEqual(b, j2)
                self.assertAlmostEqual(c, j3)
    def test_just_barely_reach_flipped_configs(self):
            print '\ntest_just_barely_reach_flipped_configs'
            for _ in xrange(0,100):
                j1 = rand_range(-180, 180)
                j2 = -90
                j3 = -89
                j4 = rand_range(-200, 200)
                j5 = rand_range(-115, 115)
                j6 = rand_range(-400, 400)

                s0 = j1,j2,j3,j4,j5,j6

                robot_info = forward_kinematics(*s0, **DH_TABLE)
                T44, debug1  = robot_info['flange'], robot_info['robot_geometry_local']
                sol = mat( inverse_kinematics_irb140(DH_TABLE, T44) )
                for s in sol.T:
                    robot_info = forward_kinematics(*s, **DH_TABLE)
                    A, debug2  = robot_info['flange'], robot_info['robot_geometry_local']
                    self.assertAlmostEqual(norm(A-T44), 0)
def backward_facing_elbow_down(dh_table, T44):
    '''
    Calculates backward-facing elbow-down.

    Note: This is in reality an elbow-down solution,
          the name merely implies it is "flipped" up-side-down
          due to the base have turned 180 degrees.
    '''
    #Geometrical paramaters
    wcp = calc_wcp(T44, 0.065)

    #First angle - j1, used to adjust a point-position
    j1 = calc_j1(wcp, flipped=True)

    p0 = mat([70e-3, 0, 352e-3])
    p0 = homogenous_rotation_z(j1)[0:3,0:3].dot(p0)

    x0 = norm(wcp[0:2] - p0[0:2])
    h1 = p0[2]
    h2 = wcp[2]
    s = h2 - h1
    x1 = norm(p0 - wcp)
    beta = 380e-3
    alpha = 360e-3

    th3 = ang_sats2(x1, alpha, beta)
    j3 = -90 + th3

    th21 = atan2(s, x0)
    th22 = atan2(beta*sin2(th3), alpha + beta*cos2(th3))
    j2 = -90 + th21 - th22

    #packing the solutions in a dynamic way
##    j4, j5, j6,\
##    j41,j51,j61, \
##    j42,j52,j62 = inverse_kinematics_spherical_wrist(dh_table, j1, j2, j3, T44)
##
##    return (j1, j2, j3, j4, j5, j6),\
##           (j1, j2, j3, j41, j51, j61), \
##           (j1, j2, j3, j42, j52, j62)
    result = pack_elbow_and_wrists(dh_table, j1, j2, j3, T44)
    return result
Ejemplo n.º 15
0
def define_plane_from_angles(origin, r, t, s, system_type='local'):
    """
        This function returns a coordinate system frame (NxN matrix),
        for a plane defined by a matrix containing a point of origin (t)
        and a set of basis vectors (R) all of dimension N: [[R, t,]
                                                            [0, 1]]
    """
    if not system_type in ['local', 'global']:
        raise ArithmeticError(
            'Only local or global coordinate system descriptions allowed')

    R = rotation_matrix_rot_tilt_skew(r, t, s)
    plane_transform = expand_matrix(R)
    plane_transform[:3, 3] = origin
    plane_transform = expand_matrix(
        mat([R[:, 0], R[:, 1], R[:, 2], origin]).T, 1, 0)

    if system_type == 'global':
        return mat_flip(plane_transform)
    else:
        return plane_transform
def elbow_down(dh_table, T44):
    '''
    Calculates forward-facing elbow-down.
    '''
    #Geometrical paramaters
    wcp = calc_wcp(T44, 0.065)

    #First angle - j1, used to adjust a point-position
    j1 = calc_j1(wcp, flipped=False)

    p0 = mat([70e-3, 0, 352e-3])
    p0 = homogenous_rotation_z(j1)[0:3,0:3].dot(p0)

    x0 = norm(wcp[0:2] - p0[0:2])
    h1 = p0[2]
    h2 = wcp[2]
    s = h2 - h1
    x1 = norm(p0 - wcp)
    beta = 380e-3
    alpha = 360e-3

    th3 = ang_sats2(x1, alpha, beta)
    j3 = -th3 - 90

    th21 = atan2(s, x0)
    th22 = atan2(beta*sin2(th3), alpha + beta*cos2(th3))
    j2 = 90 - (th21 - th22)
    if norm(wcp[:2])-norm(p0[:2]) < 0:
        j2 = -90 + (th21+th22)
##        j3 = -90-th3

##    j4, j5, j6,\
##    j41,j51,j61, \
##    j42,j52,j62 = inverse_kinematics_spherical_wrist(dh_table, j1, j2, j3, T44)
##
##    return (j1, j2, j3, j4, j5, j6),\
##           (j1, j2, j3, j41, j51, j61), \
##           (j1, j2, j3, j42, j52, j62)
    result = pack_elbow_and_wrists(dh_table, j1, j2, j3, T44)
    return result
    def test_non_reach_config(self):
            print '\ntest_non_reach_configs'
            for _ in xrange(0,100):
                j1 = rand_range(-180, 180)
                j2 = 90
                j3 = -89
                j4 = rand_range(-200, 200)
                j5 = rand_range(-115, 115)
                j6 = rand_range(-400, 400)

                s0 = j1,j2,j3,j4,j5,j6

                robot_info = forward_kinematics(*s0, **DH_TABLE)
                T44, debug1  = robot_info['flange'], robot_info['robot_geometry_local']
                sol = mat( inverse_kinematics_irb140(DH_TABLE, T44) )
                sol = sol.T

                for i,s in enumerate(sol):
                    robot_info = forward_kinematics(*s, **DH_TABLE)
                    A, debug2  = robot_info['flange'], robot_info['robot_geometry_local']
                    if i in [l+m*8 for m,_ in enumerate(range(0, len(sol), 8)) for l in [0,1,4,5]]: #all non-flipped solutions only
                        self.assertAlmostEqual(norm(A-T44), 0)
                    else:
                        self.assertTrue(n.isnan(norm(A-T44)))
Ejemplo n.º 18
0
def ang(R):
    return mat(rot_tilt_skew(R))
def inverse_kinematics_curve(trans_frames):
    # perform inverse kinematics over a curve and collect all solutions
    all_solutions = []
    for point_frame in trans_frames:
        all_solutions.append(__inverse_kinematics_pose(point_frame, filtering=True))
    return mat(all_solutions)
Ejemplo n.º 20
0
    d,e,f = rots2.shape

    Y = rots1.reshape(a*b, c)
    Z = rots2.reshape(d*e, f)

    B = Y.T.dot(Y)
    C = Y.T.dot(Z)
    A = solve(B,C)
    return fit_to_ori(A)

# ranges:
# rot = (-pi, pi)
# tilt = (-pi/2, pi/2)
# skew = (-pi, pi)

e = lambda mag: mat([rnd(-1, 1)*(10**mag) for _ in xrange(9)]).reshape(3,3)

def ang(R):
    return mat(rot_tilt_skew(R))

def apply_noise(R, mag=-4):
    return R + e(mag)

if __name__ == "__main__":
    res = {"solerr1":[],
           "solerr2":[],
           "solerr32":[],
           "angerr1":[],
           "angerr2":[],
           "angerr32":[],
           }
def generate_modulo_solutions(solution_matrix, index, modulo=360.0):
    return mat(zip(*__modulo_solutions(solution_matrix, index, modulo)))
Ejemplo n.º 22
0
def mat_flip3(M):
    transf_flip = mat([[1, 0, 0], [0, -1, 0], [0, 0, -1]])
    return transf_flip.dot(M)
Ejemplo n.º 23
0
def forward_kinematics(*joint_values, **kwargs):
    """
    Performs the denavit-hartenberg algorithm
    and calculates T44 = A0 * A1 * A2 * ... * An multiplication.

    The parameters are entered in the order A, alpha, D, theta repeatedly
    if no order is specified. However, is another order specified then
    the values must be entered in that order.
    """

    # check so that only supported parameters
    # exist in kwargs and abort if any other parameter
    # had been created by mistake due to typos or similar
    if not kwargs.has_key('tool'):
        kwargs['tool'] = None
        print 'NO TOOL'
    tool = kwargs['tool']

    input_param_diff = set(kwargs) - set(
        ['order', 'convention', 'unit', 'table', 'tool'])
    if len(input_param_diff) > 0:
        raise Exception('Unsupported parameters: ' + str(*input_param_diff))

    # handle which unit is being used
    if not kwargs.has_key('unit'):
        kwargs['unit'] = 'metre'
    elif kwargs['unit'] == 'm':
        kwargs['unit'] = 'metre'
    elif kwargs['unit'] == 'mm':
        kwargs['unit'] = 'millimetre'

    # supply a standard order
    if not kwargs.has_key('order'):
        kwargs['order'] = ['A', 'alpha', 'D', 'theta']

    # supply the standard denivit-hartenberg if no convention given
    if not kwargs.has_key('convention'):
        kwargs['convention'] = 'standard'

    row_length = 5
    nbr_of_joints = len(joint_values)
    if len(kwargs['table']) == 1 and type(kwargs['table'][0]) in [list, tuple]:
        raise ArithmeticError(
            "Function does not use lists or tuples, please unpack using * operator."
        )
    elif not (len(kwargs['table']) % row_length == 0):
        raise ArithmeticError(
            "Invalid number of Denavit-Hartenberg parameters - you also need to supply type of joint"
        )

    matrices = []
    for k in xrange(0, nbr_of_joints):
        # Performing the operation
        # A, alpha, D, theta = params['A'], params['alpha'], params['D'], params['theta']
        # in a very general way
        var_names, var_values, joint_type = kwargs['order'],\
                                            kwargs['table'][row_length*k : row_length*k + row_length-1],\
                                            kwargs['table'][row_length*k + row_length-1]
        for i in xrange(row_length - 1):
            exec('%s = %0.16f' % (var_names[i], var_values[i]))

        if kwargs['unit'] == 'mm' or kwargs['unit'] == 'millimetre':
            A = A * 1e-3  #converts mm to meters
            D = D * 1e-3  #convers mm to meters
        elif kwargs['unit'] == 'm' or kwargs['unit'] == 'metre':
            pass
        else:
            raise ArithmeticError("Unknown unit of length, only meters('m' or 'metre')"+\
            +" or millimeters ('mm' or 'millimetre') allowed.")
        if joint_type == 'R':
            matrices.append(
                transform_to_next(A, alpha, D, theta + joint_values[k]))
        elif joint_type == 'P':
            matrices.append(
                transform_to_next(A, alpha, D + joint_values[k], theta))

    # collect information about the Denivit-Hartenberg table
    dh_table = {
        'table': kwargs['table'],
        'unit': kwargs['unit'],
        'convention': kwargs['convention'],
        'order': kwargs['order'],
        'tool': kwargs['tool']
    }

    global_geometry = matmul_series(*matrices)
    global_geometry.insert(0, homogenous_matrix(0, 0, 0, 0, 0, 0))

    flange = matmul(*matrices)
    if tool is None:
        tcp = mat(flange)
    else:
        tcp = flange.dot(tool)

    result = {
        'flange': flange,
        'tcp': tcp,
        'robot_geometry_local': matrices,
        'robot_geometry_global': global_geometry,
        'dh_table': dh_table
    }

    # perform matrix chain-multiplication / serial-multiplication with matrix product
    return result
def merge_solutions(*args):
    result = []
    for m in args:
        result += zip(*m)
    return mat(zip(*result))