def plotFeasibleAccPolytope(self, range_plot=2.0):
     from pinocchio_inv_dyn.geom_utils import plot_inequalities
     ax = plot_inequalities(np.vstack([self.a,self.b]).T, self.d, [-range_plot,range_plot], [-range_plot,range_plot]);
     plt.axis([0,range_plot,-range_plot,0])
     plt.title('Feasible com pos-acc');
     plut.movePlotSpines(ax, [0, 0]);
     ax.set_xlabel('com pos');
     ax.set_ylabel('com acc');
     plt.show();
예제 #2
0
def can_I_stop(c0,
               dc0,
               contact_points,
               contact_normals,
               mu,
               mass,
               T_0,
               MAX_ITER=1000,
               DO_PLOTS=False,
               verb=0,
               eliminate_redundancies=False):
    ''' Determine whether the system can come to a stop without changing contacts.
        Keyword arguments:
        c0 -- initial CoM position 
        dc0 -- initial CoM velocity 
        contact points -- a matrix containing the contact points
        contact normals -- a matrix containing the contact normals
        mu -- friction coefficient (either a scalar or an array)
        mass -- the robot mass
        T_0 -- an initial guess for the time to stop
        Output: (is_stable, c_final, dc_final), where:
        is_stable -- boolean value
        c_final -- final com position
        dc_final -- final com velocity
    '''
    #        Steps:
    #            - Compute GIWC: H*w <= h, where w=(m*(g-ddc), m*cx(g-ddc))
    #            - Project GIWC in (alpha,DDalpha) space, where c=c0+alpha*v, ddc=-DDalpha*v, v=dc0/||dc0||: A*(alpha,DDalpha)<=b
    #            - Find ordered (left-most first, clockwise) vertices of 2d polytope A*(alpha,DDalpha)<=b: V
    #            - Initialize: alpha=0, Dalpha=||dc0||
    #            - LOOP:
    #                - Find current active inequality: a*alpha + b*DDalpha <= d (i.e. DDalpha upper bound for current alpha value)
    #                - If DDalpha_upper_bound<0: return False
    #                - Find alpha_max (i.e. value of alpha corresponding to right vertex of active inequality)
    #                - Initialize: t=T_0, t_ub=10, t_lb=0
    #                LOOP:
    #                    - Integrate LDS until t: DDalpha = d/b - (a/d)*alpha
    #                    - if(Dalpha(t)==0 && alpha(t)<=alpha_max):  return (True, alpha(t)*v)
    #                    - if(alpha(t)==alpha_max && Dalpha(t)>0):   alpha=alpha(t), Dalpha=Dalpha(t), break
    #                    - if(alpha(t)<alpha_max && Dalpha>0):       t_lb=t, t=(t_ub+t_lb)/2
    #                    - else                                      t_ub=t, t=(t_ub+t_lb)/2
    assert mass > 0.0, "Mass is not positive"
    assert T_0 > 0.0, "Time is not positive"
    assert mu > 0.0, "Friction coefficient is not positive"
    c0 = np.asarray(c0).squeeze()
    dc0 = np.asarray(dc0).squeeze()
    contact_points = np.asarray(contact_points)
    contact_normals = np.asarray(contact_normals)
    assert c0.shape[0] == 3, "Com position has not size 3"
    assert dc0.shape[0] == 3, "Com velocity has not size 3"
    assert contact_points.shape[1] == 3, "Contact points have not size 3"
    assert contact_normals.shape[1] == 3, "Contact normals have not size 3"
    assert contact_points.shape[0] == contact_normals.shape[
        0], "Number of contact points and contact normals do not match"

    g_vector = np.array([0, 0, -9.81])
    (H, h) = compute_GIWC(contact_points,
                          contact_normals,
                          mu,
                          eliminate_redundancies=eliminate_redundancies)

    # If initial com velocity is zero then test static equilibrium
    if (np.linalg.norm(dc0) < EPS):
        w = np.zeros(6)
        w[2] = -mass * 9.81
        w[3:] = mass * np.cross(c0, g_vector)
        if (np.max(np.dot(H, w) - h) < EPS):
            return (True, c0, dc0)
        return (False, c0, dc0)

    # Project GIWC in (alpha,DDalpha) space, where c=c0+alpha*v, ddc=DDalpha*v, v=dc0/||dc0||: a*alpha + b*DDalpha <= d
    v = dc0 / np.linalg.norm(dc0)
    K = np.zeros((6, 3))
    K[:3, :] = mass * np.identity(3)
    K[3:, :] = mass * crossMatrix(c0)
    d = h - np.dot(H, np.dot(K, g_vector))
    b = np.dot(np.dot(-H, K), v)
    # vector multiplying com acceleration
    tmp = np.array([
        [0, 0, 0, 0, 1, 0],  #temp times the variation dc will result in 
        [0, 0, 0, -1, 0, 0],  # [ 0 0 0 dc_y -dc_x 0]^T
        [0, 0, 0, 0, 0, 0]
    ]).T
    a = mass * 9.81 * np.dot(np.dot(H, tmp), v)

    if (DO_PLOTS):
        range_plot = 10
        ax = plot_inequalities(
            np.vstack([a, b]).T, d, [-range_plot, range_plot],
            [-range_plot, range_plot])
        plt.axis([0, range_plot, -range_plot, 0])
        plt.title('Feasible com pos-acc')
        plut.movePlotSpines(ax, [0, 0])
        ax.set_xlabel('com pos')
        ax.set_ylabel('com acc')
        plt.show()

    # Eliminate redundant inequalities
    if (eliminate_redundancies):
        A_red, d = eliminate_redundant_inequalities(np.vstack([a, b]).T, d)
        a = A_red[:, 0]
        b = A_red[:, 1]

    # Normalize inequalities to have unitary coefficients for DDalpha: b*DDalpha <= d - a*alpha
    for i in range(a.shape[0]):
        if (abs(b[i]) > EPS):
            a[i] /= abs(b[i])
            d[i] /= abs(b[i])
            b[i] /= abs(b[i])
        elif (verb > 0):
            print "WARNING: cannot normalize %d-th inequality because coefficient of DDalpha is almost zero" % i, b[
                i]

    # Initialize: alpha=0, Dalpha=||dc0||
    alpha = 0
    Dalpha = np.linalg.norm(dc0)

    #sort b indices to only keep negative values
    negative_ids = np.where(b < 0)[0]
    if (negative_ids.shape[0] == 0):
        # CoM acceleration is unbounded
        return (True, c0, 0.0 * v)

    for iiii in range(MAX_ITER):
        # Find current active inequality: b*DDalpha <= d - a*alpha (i.e. DDalpha lower bound for current alpha value)
        a_alpha_d = a * alpha - d
        a_alpha_d_negative_bs = a_alpha_d[negative_ids]
        (i_DDalpha_min, DDalpha_min) = [
            (i, a_min)
            for (i, a_min) in [(j, a_alpha_d[j]) for j in negative_ids]
            if (a_min >= a_alpha_d_negative_bs).all()
        ][0]
        if (verb > 0):
            print "DDalpha_min", DDalpha_min
            print "i_DDalpha_min", i_DDalpha_min

        # If DDalpha_lower_bound>0: return False
        if (DDalpha_min >= -EPS):
            if (verb > 0):
                print "Algorithm converged because DDalpha is positive"
            return (False, c0 + alpha * v, Dalpha * v)

        # Find alpha_max (i.e. value of alpha corresponding to right vertex of active inequality)
        den = b * a[i_DDalpha_min] + a
        i_pos = np.where(den > 0)[0]
        if (i_pos.shape[0] == 0):
            #            print "WARNING b*a_i0+a is never positive, that means that alpha_max is unbounded";
            alpha_max = 10.0
        else:
            alpha_max = np.min(
                (d[i_pos] + b[i_pos] * d[i_DDalpha_min]) / den[i_pos])
            if (verb > 0):
                print "alpha_max", alpha_max
        if (alpha_max < alpha):
            # We reach the right limit of the polytope of feasible com pos-acc.
            # This means there is no feasible com acc for farther com position (with zero angular momentum derivative)
            return (False, c0 + alpha * v, Dalpha * v)

        # If DDalpha is not always negative on the current segment then update alpha_max to the point
        # where the current segment intersects the x axis
        if (a[i_DDalpha_min] * alpha_max - d[i_DDalpha_min] > 0.0):
            alpha_max = d[i_DDalpha_min] / a[i_DDalpha_min]
            if (verb > 0):
                print "Updated alpha_max", alpha_max

        # Initialize: t=T_0, t_ub=10, t_lb=0
        t = T_0
        t_ub = 10
        t_lb = 0
        if (abs(a[i_DDalpha_min]) > EPS):
            omega = sqrt(a[i_DDalpha_min] + 0j)
            if (verb > 0):
                print "omega", omega
        else:
            # if the acceleration is constant over time I can compute directly the time needed
            # to bring the velocity to zero:
            #     Dalpha(t) = Dalpha(0) + t*DDalpha = 0
            #     t = -Dalpha(0)/DDalpha
            t = Dalpha / d[i_DDalpha_min]
            alpha_t = alpha + t * Dalpha - 0.5 * t * t * d[i_DDalpha_min]
            if (alpha_t <= alpha_max + EPS):
                if (verb > 0):
                    print "DDalpha_min is independent from alpha, algorithm converged to Dalpha=0"
                return (True, c0 + alpha_t * v, 0.0 * v)
            # if alpha reaches alpha_max before the velocity is zero, then compute the time needed to reach alpha_max
            #     alpha(t) = alpha(0) + t*Dalpha(0) + 0.5*t*t*DDalpha = alpha_max
            #     t = (- Dalpha(0) +/- sqrt(Dalpha(0)^2 - 2*DDalpha(alpha(0)-alpha_max))) / DDalpha;
            # where DDalpha = -d[i_DDalpha_min]
            # Having two solutions, we take the smallest one because we want to find the first time
            # at which alpha reaches alpha_max
            delta = sqrt(Dalpha**2 + 2 * d[i_DDalpha_min] *
                         (alpha - alpha_max))
            t = (Dalpha - delta) / d[i_DDalpha_min]
            if (t < 0.0):
                # If the smallest time at which alpha reaches alpha_max is negative print a WARNING because this should not happen
                print "WARNING: Time is less than zero:", t, alpha, Dalpha, d[
                    i_DDalpha_min], alpha_max
                t = (Dalpha + delta) / d[i_DDalpha_min]
                if (t < 0.0):
                    # If also the largest time is negative print an ERROR and return
                    print "ERROR: Time is still less than zero:", t, alpha, Dalpha, d[
                        i_DDalpha_min], alpha_max
                    return (False, c0 + alpha * v, Dalpha * v)

        bisection_converged = False
        for jjjj in range(MAX_ITER):
            # Integrate LDS until t: DDalpha = a*alpha - d
            if (abs(a[i_DDalpha_min]) > EPS):
                # if a=0 then the acceleration is a linear function of the position and I need to use this formula to integrate
                sh = np.sinh(omega * t)
                ch = np.cosh(omega * t)
                alpha_t = ch * alpha + sh * Dalpha / omega + (1 - ch) * (
                    d[i_DDalpha_min] / a[i_DDalpha_min])
                Dalpha_t = omega * sh * alpha + ch * Dalpha - omega * sh * (
                    d[i_DDalpha_min] / a[i_DDalpha_min])
            else:
                # if a=0 then the acceleration is constant and I need to use this formula to integrate
                alpha_t = alpha + t * Dalpha - 0.5 * t * t * d[i_DDalpha_min]
                Dalpha_t = Dalpha - t * d[i_DDalpha_min]

            if (np.imag(alpha_t) != 0.0):
                print "ERROR alpha is imaginary", alpha_t
                return (False, c0 + alpha * v, Dalpha * v)
            if (np.imag(Dalpha_t) != 0.0):
                print "ERROR Dalpha is imaginary", Dalpha_t
                return (False, c0 + alpha * v, Dalpha * v)

            alpha_t = np.real(alpha_t)
            Dalpha_t = np.real(Dalpha_t)
            if (verb > 0):
                print "Bisection iter", jjjj, "alpha", alpha_t, "Dalpha", Dalpha_t, "t", t

            if (abs(Dalpha_t) < EPS and alpha_t <= alpha_max + EPS):
                if (verb > 0):
                    print "Algorithm converged to Dalpha=0"
                return (True, c0 + alpha_t * v, Dalpha_t * v)
            if (abs(alpha_t - alpha_max) < EPS and Dalpha_t > 0):
                alpha = alpha_max + EPS
                Dalpha = Dalpha_t
                bisection_converged = True
                break
            if (alpha_t < alpha_max and Dalpha_t > 0):
                t_lb = t
                t = (t_ub + t_lb) / 2
            else:
                t_ub = t
                t = (t_ub + t_lb) / 2

        if (not bisection_converged):
            print "ERROR: Bisection search did not converge in %d iterations" % MAX_ITER
            return (False, c0 + alpha * v, Dalpha * v)

    print "ERROR: Numerical integration did not converge in %d iterations" % MAX_ITER
    if (DO_PLOTS):
        plt.show()

    return (False, c0 + alpha * v, Dalpha * v)
예제 #3
0
def test(N_CONTACTS=2, verb=0, solver='qpoases'):
    from math import atan, pi
    from pinocchio_inv_dyn.multi_contact.utils import generate_contacts, find_static_equilibrium_com, compute_GIWC, compute_support_polygon
    import pinocchio_inv_dyn.plot_utils as plut
    from pinocchio_inv_dyn.geom_utils import plot_inequalities
    import matplotlib.pyplot as plt

    np.set_printoptions(precision=2, suppress=True, linewidth=250)
    DO_PLOTS = True
    PLOT_3D = False
    mass = 75
    # mass of the robot
    g_vector = np.array([0, 0, -9.81])
    mu = 0.5
    # friction coefficient
    lx = 0.1
    # half foot size in x direction
    ly = 0.07
    # half foot size in y direction
    USE_DIAGONAL_GENERATORS = True
    GENERATE_QUASI_FLAT_CONTACTS = False
    #First, generate a contact configuration
    CONTACT_POINT_UPPER_BOUNDS = [0.5, 0.5, 0.5]
    CONTACT_POINT_LOWER_BOUNDS = [-0.5, -0.5, 0.0]
    gamma = atan(mu)
    # half friction cone angle
    RPY_LOWER_BOUNDS = [-2 * gamma, -2 * gamma, -pi]
    RPY_UPPER_BOUNDS = [+2 * gamma, +2 * gamma, +pi]
    MIN_CONTACT_DISTANCE = 0.3

    X_MARG = 0.07
    Y_MARG = 0.07

    succeeded = False

    while (succeeded == False):
        (p,
         N) = generate_contacts(N_CONTACTS, lx, ly, mu,
                                CONTACT_POINT_LOWER_BOUNDS,
                                CONTACT_POINT_UPPER_BOUNDS, RPY_LOWER_BOUNDS,
                                RPY_UPPER_BOUNDS, MIN_CONTACT_DISTANCE,
                                GENERATE_QUASI_FLAT_CONTACTS)
        X_LB = np.min(p[:, 0] - X_MARG)
        X_UB = np.max(p[:, 0] + X_MARG)
        Y_LB = np.min(p[:, 1] - Y_MARG)
        Y_UB = np.max(p[:, 1] + Y_MARG)
        Z_LB = np.min(p[:, 2] - 0.05)
        Z_UB = np.max(p[:, 2] + 1.5)
        (H, h) = compute_GIWC(p, N, mu, False, USE_DIAGONAL_GENERATORS)
        (succeeded, c0) = find_static_equilibrium_com(mass, [X_LB, Y_LB, Z_LB],
                                                      [X_UB, Y_UB, Z_UB], H, h)

    dc0 = np.random.uniform(-1, 1, size=3)
    dc0[2] = 0

    if (PLOT_3D):
        fig = plt.figure(figsize=plt.figaspect(0.5) * 1.5)
        ax = fig.gca(projection='3d')
        line_styles = ["b", "r", "c", "g"]
        ss = [0.05, 0.1, 0.15, 0.2, 0.25, 0.3]
        ax.scatter(c0[0], c0[1], c0[2], c='k', marker='o')
        for i in range(p.shape[0]):
            ax.scatter(p[i, 0],
                       p[i, 1],
                       p[i, 2],
                       c=line_styles[i % len(line_styles)],
                       marker='o')
            for s in ss:
                ax.scatter(p[i, 0] + s * N[i, 0],
                           p[i, 1] + s * N[i, 1],
                           p[i, 2] + s * N[i, 2],
                           c=line_styles[i % len(line_styles)],
                           marker='x')
        for s in ss:
            ax.scatter(c0[0] + s * dc0[0],
                       c0[1] + s * dc0[1],
                       c0[2] + s * dc0[2],
                       c='k',
                       marker='x')
        ax.set_xlabel('x')
        ax.set_ylabel('y')
        ax.set_zlabel('z')

    a = dc0 / np.linalg.norm(dc0)
    equiLP = EquilibriumExtremumLP("quiLP",
                                   p,
                                   N,
                                   mu,
                                   g_vector,
                                   mass,
                                   a,
                                   c0,
                                   verb=verb,
                                   solver=solver)
    (status, com_extr) = equiLP.find_extreme_com_position()
    print "status", optim.LP_status_string[status], "com", com_extr

    if (DO_PLOTS):
        f, ax = plut.create_empty_figure()
        for j in range(p.shape[0]):
            ax.scatter(p[j, 0], p[j, 1], c='k', s=100)
        ax.scatter(c0[0], c0[1], c='r', s=100)
        com_x = np.zeros(2)
        com_y = np.zeros(2)
        com_x[0] = c0[0]
        com_y[0] = c0[1]
        com_x[1] = c0[0] + 0.1 * dc0[0]
        com_y[1] = c0[1] + 0.1 * dc0[1]
        ax.plot(com_x, com_y, color='b')
        ax.scatter(com_extr[0], com_extr[1], c='r', s=100)
        plt.axis([X_LB, X_UB, Y_LB, Y_UB])
        plt.title('Contact Points and CoM position')

        (H, h) = compute_GIWC(p, N, mu)
        (B_sp, b_sp) = compute_support_polygon(H,
                                               h,
                                               mass,
                                               g_vector,
                                               eliminate_redundancies=False)
        X_MIN = np.min(p[:, 0])
        X_MAX = np.max(p[:, 0])
        X_MIN -= 0.1 * (X_MAX - X_MIN)
        X_MAX += 0.1 * (X_MAX - X_MIN)
        Y_MIN = np.min(p[:, 1])
        Y_MAX = np.max(p[:, 1])
        Y_MIN -= 0.1 * (Y_MAX - Y_MIN)
        Y_MAX += 0.1 * (Y_MAX - Y_MIN)
        plot_inequalities(B_sp,
                          b_sp, [X_MIN, X_MAX], [Y_MIN, Y_MAX],
                          ax=ax,
                          color='b',
                          lw=4)
        plt.show()