Example #1
0
def body2ast(time, state, ast, dum):
    """Convert state from the body frame to the asteroid fixed frame

    This function will convert the state output of eoms_inertial to the asteroid fixed frame.
    This wil allow for comparision with the state from eoms_relative.

    Inputs:
        time - nx1 array of time stamps for the state vector
        state - nx18 array of the state vector defined as follows:
            inertial_pos - state[:, 0:3] is the position of the body with respect to the asteroid 
                center and defined in the inertial frame
            inertial_vel - state[:, 4:6] is the velocity of the sc with respect to the asteroid 
                center of mass and defined in the inertial frame
            R_sc2int - state[:, 6:15] the rotation matrix which transforms vectors from the sc frame
                to the inertial frame
            body_w - state[:, 15:18] the angular velocity of the sc with respect to the inertial
                frame and defined in the spacecraft frame
        ast - Instance of Asteroid class
        dum - Instance of Dumbbell class

    Outputs:
        ast_state - the state as represented in the rotating asteroid frame
            ast_pos - ast_state[:, 0:3] is the position of the sc with respect to the asteroid
                fixed frame and represented in the asteroid frame
            ast_vel - ast_state[:, 3:6] is the velocity of the sc with respect to the asteroid and 
                represented in the asteroid fixed frame
            ast_R_sc2ast - ast_state[:, 6:15] is the transformation from the sc frame to the asteroid
                frame
            ast_w - ast_state[:, 15:18] is the angular velocity of the sc with respect to the inertial 
                frame and defined in the asteroid frame
    """
    # transformation between asteroid fixed frame and inertial frame
    # figure out transformation from inertial frame to relative frame
    Rast2int = np.zeros((3, 3, time.shape[0]))
    Rint2ast = np.zeros((3, 3, time.shape[0]))

    ast_state = np.zeros(state.shape)

    for ii, t in np.ndenumerate(time):
        Rast2int[:, :, ii] = attitude.rot3(
            ast.omega * t,
            'c')[:, :, np.newaxis]  # asteroid body frame to inertial frame
        Rint2ast[:, :, ii] = attitude.rot3(ast.omega * t, 'c').T[:, :,
                                                                 np.newaxis]

        Ra = np.squeeze(Rast2int[:, :, ii])
        # convert the relative state to the inertial frame
        body_pos = np.squeeze(state[ii, 0:3])
        body_vel = np.squeeze(state[ii, 3:6])
        R_sc2int = np.squeeze(state[ii, 6:15].reshape(3, 3))
        body_w = np.squeeze(state[ii, 15:18])

        ast_pos = Ra.T.dot(body_pos)
        ast_vel = Ra.T.dot(body_vel)
        ast_R_sc2ast = Ra.T.dot(R_sc2int).reshape(9)
        ast_w = ast_R_sc2ast.reshape((3, 3)).dot(body_w)

        ast_state[ii, :] = np.hstack((ast_pos, ast_vel, ast_R_sc2ast, ast_w))

    return ast_states
Example #2
0
def pqw2eci(raan, argp, inc):
    r"""Return rotation matrix to go from PQW to ECI

    Returns the rotation matrix to transform a vector represented in the perifocal
    frame to the inertial frame.

    Parameters
    ----------
    raan : float 
        Right ascension of the ascending node in radians
    argp : float
        Argument of periapsis in radians
    inc : float
        inclination of orbit in radians

    Returns
    -------
    PQW2ECI : ndarray
        3x3 numpy array defining the rotation matrix

    Author
    ------
    Shankar Kulumani		GWU		[email protected]
    """
    PQW2ECI = attitude.rot3(raan).dot(attitude.rot1(inc)).dot(
        attitude.rot3(argp))
    print(PQW2ECI)
    return PQW2ECI
Example #3
0
def dcm_pqw2eci_coe(raan, inc, arg_p):
    """Define rotation matrix transforming PQW to ECI given orbital elements

    """
    dcm = attitude.rot3(raan).dot(
            attitude.rot1(inc)).dot(attitude.rot3(arg_p))

    dcm_pqw2eci = attitude.rot3(-raan, 'r').dot(attitude.rot1(-inc, 'r')
                                                ).dot(attitude.rot3(-arg_p, 'r'))
    return dcm
Example #4
0
class TestEulerRot90_column():
    angle = np.pi / 2
    b1 = np.array([1, 0, 0])
    b2 = np.array([0, 1, 0])
    b3 = np.array([0, 0, 1])

    R1 = attitude.rot1(angle, 'c')
    R2 = attitude.rot2(angle, 'c')
    R3 = attitude.rot3(angle, 'c')

    R1_row = attitude.rot1(angle, 'r')
    R2_row = attitude.rot2(angle, 'r')
    R3_row = attitude.rot3(angle, 'r')

    def test_rot1_transpose(self):
        np.testing.assert_allclose(self.R1_row, self.R1.T)

    def test_rot2_transpose(self):
        np.testing.assert_allclose(self.R2_row, self.R2.T)

    def test_rot3_transpose(self):
        np.testing.assert_allclose(self.R3_row, self.R3.T)

    def test_rot1_90_b1(self):
        np.testing.assert_array_almost_equal(self.R1.dot(self.b1), self.b1)

    def test_rot1_90_b2(self):
        np.testing.assert_array_almost_equal(self.R1.dot(self.b2), self.b3)

    def test_rot1_90_b3(self):
        np.testing.assert_array_almost_equal(self.R1.dot(self.b3), -self.b2)

    def test_rot2_90_b1(self):
        np.testing.assert_array_almost_equal(self.R2.dot(self.b1), -self.b3)

    def test_rot2_90_b2(self):
        np.testing.assert_array_almost_equal(self.R2.dot(self.b2), self.b2)

    def test_rot2_90_b3(self):
        np.testing.assert_array_almost_equal(self.R2.dot(self.b3), self.b1)

    def test_rot3_90_b1(self):
        np.testing.assert_array_almost_equal(self.R3.dot(self.b1), self.b2)

    def test_rot3_90_b2(self):
        np.testing.assert_array_almost_equal(self.R3.dot(self.b2), -self.b1)

    def test_rot3_90_b3(self):
        np.testing.assert_array_almost_equal(self.R3.dot(self.b3), self.b3)
Example #5
0
 def test_dcm_loop(self):
     latitude = np.linspace(-np.pi/2, np.pi/2, 10)
     longitude = np.linspace(-np.pi, np.pi, 10)
     for lat, lon in zip(latitude, longitude):
         dcm_expected = rot2(np.pi/2 - lat, 'r').dot(rot3(lon, 'r'))
         dcm = transform.dcm_ecef2sez(lat, lon)
         np.testing.assert_allclose(dcm, dcm_expected)
Example #6
0
 def test_dcm_loop(self):
     latitude = np.linspace(-np.pi / 2, np.pi / 2, 10)
     longitude = np.linspace(-np.pi, np.pi, 10)
     for lat, lon in zip(latitude, longitude):
         dcm_expected = rot2(np.pi / 2 - lat, 'r').dot(rot3(lon, 'r'))
         dcm = transform.dcm_ecef2sez(lat, lon)
         np.testing.assert_allclose(dcm, dcm_expected)
 def test_expm_rot3_derivative(self):
     axis = np.array([0, 0, 1])
     R_dot = self.alpha * attitude.hat_map(axis).dot(
         scipy.linalg.expm(self.alpha * self.t * attitude.hat_map(axis)))
     R3_dot = attitude.rot3(self.alpha * self.t).dot(
         attitude.hat_map(self.alpha * axis))
     np.testing.assert_almost_equal(R_dot, R3_dot)
Example #8
0
    def eoms_inertial(self, state, t, ast):
        """Inertial dumbbell equations of motion about an asteroid
        
        Inputs:
            t - 
            state -
            ast - Asteroid class object holding the asteroid gravitational model and
            other useful parameters
        """
        # unpack the state
        pos = state[0:
                    3]  # location of the center of mass in the inertial frame
        vel = state[3:6]  # vel of com in inertial frame
        R = np.reshape(state[6:15], (3, 3))  # sc body frame to inertial frame
        ang_vel = state[
            15:
            18]  # angular velocity of sc wrt inertial frame defined in body frame

        Ra = attitude.rot3(ast.omega * t,
                           'c')  # asteroid body frame to inertial frame

        # unpack parameters for the dumbbell
        J = self.J

        rho1 = self.zeta1
        rho2 = self.zeta2

        # position of each mass in the asteroid frame
        z1 = Ra.T.dot(pos + R.dot(rho1))
        z2 = Ra.T.dot(pos + R.dot(rho2))

        z = Ra.T.dot(pos)  # position of COM in asteroid frame

        # compute the potential at this state
        (U1, U1_grad, U1_grad_mat, U1laplace) = ast.polyhedron_potential(z1)
        (U2, U2_grad, U2_grad_mat, U2laplace) = ast.polyhedron_potential(z2)

        F1 = self.m1 * Ra.dot(U1_grad)
        F2 = self.m2 * Ra.dot(U2_grad)

        M1 = self.m1 * attitude.hat_map(rho1).dot(R.T.dot(Ra).dot(U1_grad))
        M2 = self.m2 * attitude.hat_map(rho2).dot(R.T.dot(Ra).dot(U2_grad))
        # M1 = np.zeros(3)
        # M2 = np.zeros_like(3)

        pos_dot = vel
        vel_dot = 1 / (self.m1 + self.m2) * (F1 + F2)
        R_dot = R.dot(attitude.hat_map(ang_vel)).reshape(9)
        ang_vel_dot = np.linalg.inv(J).dot(-np.cross(ang_vel, J.dot(ang_vel)) +
                                           M1 + M2)

        statedot = np.hstack((pos_dot, vel_dot, R_dot, ang_vel_dot))

        return statedot
Example #9
0
def traverse_then_land_vertically(time,
                                  ast,
                                  final_pos=[0.550, 0, 0],
                                  initial_pos=[2.550, 0, 0],
                                  descent_tf=3600):
    """Desired translational states for vertical landing on asteroid
   
    First the spacecraft will traverse horizontally in the equatorial plane
    over the asteroid fixed x axis, then descend vertically

    Inputs :
    --------
    
    """
    if time < descent_tf:
        # linear interpolation between whatever the current state is and the landing staging point
        omega = np.pi / 2 / descent_tf
        inertial_pos = 2.550 * np.array(
            [np.sin(omega * time), -np.cos(omega * time), 0])
        inertial_vel = 2.550 * omega * np.array(
            [np.cos(omega * time),
             np.sin(omega * time), 0])
        inertial_accel = 2.550 * omega**2 * np.array(
            [-np.sin(omega * time),
             np.cos(omega * time), 0])

    else:
        # rotation state of the asteroid - assume all simulations start with asteroid aligned with the inertial frame
        omega_ast = ast.omega
        omega_ast_dot = 0

        omega_ast_vec = np.array([0, 0, omega_ast])
        omega_ast_dot_vec = np.zeros(3)

        Ra2i = attitude.rot3(omega_ast * (time - descent_tf), 'c')
        # determine desired position and velocity in the body fixed frame at this current time input
        # we'll use a simple linear interpolation between initial and final states
        xslope = (final_pos[0] - initial_pos[0]) / (
            descent_tf)  # how long for teh descent
        xdes = xslope * (time - descent_tf) + initial_pos[0]

        body_pos_des = np.array([xdes, 0, 0])
        body_vel_des = np.array([xslope, 0, 0])
        body_acc_des = np.zeros(3)
        # transform this body position/velocity into the inertial frame
        inertial_pos = Ra2i.dot(body_pos_des)
        inertial_vel = body_vel_des + np.cross(omega_ast_vec, body_pos_des)
        inertial_accel = body_acc_des + 2 * np.cross(
            omega_ast_vec, body_vel_des) + np.cross(
                omega_ast_vec, np.cross(omega_ast_vec, body_pos_des))

    # output
    return inertial_pos, inertial_vel, inertial_accel
Example #10
0
def dcm_eci2ecef(jd):
    """Rotation matrix to convert from ECI to ECEF

    Will gradually improve this function to include all of the Earth
    motion terms. For now, just use sidereal time to get the rotation matrix
    """

    gst, _ = time.gstlst(jd, 0)

    dcm = attitude.rot3(gst, 'r')

    return dcm
Example #11
0
class TestEulerRotInvalid():
    R1 = attitude.rot1(0, 'x')
    R2 = attitude.rot2(0, 'x')
    R3 = attitude.rot3(0, 'x')
    invalid = 1

    def test_rot1_invalid(self):
        np.testing.assert_allclose(self.R1, self.invalid)

    def test_rot2_invalid(self):
        np.testing.assert_allclose(self.R2, self.invalid)

    def test_rot3_invalid(self):
        np.testing.assert_allclose(self.R3, self.invalid)
Example #12
0
def castalia_raycasting_plot(img_path):
    """Generate an image of the raycaster in work
    """
    if not os.path.exists(img_path):
        os.makedirs(img_path)

    output_filename = os.path.join(img_path, 'castalia_raycasting_plot.jpg')

    input_filename = './data/shape_model/CASTALIA/castalia.obj'
    polydata = wavefront.read_obj_to_polydata(input_filename)

    # initialize the raycaster
    caster_obb = raycaster.RayCaster(polydata, flag='obb')
    caster_bsp = raycaster.RayCaster(polydata, flag='bsp')

    sensor = raycaster.Lidar(view_axis=np.array([1, 0, 0]), num_step=3)

    # need to translate the sensor and give it a pointing direction
    pos = np.array([2, 0, 0])
    dist = 2  # distance for each raycast
    R = attitude.rot3(np.pi)

    # find the inersections
    # targets = pos + sensor.rotate_fov(R) * dist
    targets = sensor.define_targets(pos, R, dist)
    intersections_obb = caster_obb.castarray(pos, targets)
    intersections_bsp = caster_bsp.castarray(pos, targets)

    # plot
    fig = graphics.mayavi_figure()

    graphics.mayavi_addPoly(fig, polydata)
    graphics.mayavi_addPoint(fig, pos, radius=0.05)

    # draw lines from pos to all targets
    for pt in targets:
        graphics.mayavi_addLine(fig, pos, pt, color=(1, 0, 0))

    for ints in intersections_bsp:
        graphics.mayavi_addPoint(fig, ints, radius=0.05, color=(1, 1, 0))

    graphics.mayavi_axes(fig=fig, extent=[-1, 1, -1, 1, -1, 1])
    graphics.mayavi_view(fig=fig)

    # savefig
    graphics.mayavi_savefig(fig=fig, filename=output_filename, magnification=4)
Example #13
0
    def inertial_energy(self, time, state, ast):
        """Compute the kinetic and potential energy of the dumbbell given the current state
        
        Input:
            vel - nx3 velocity in inertial frame (km/sec)
            ang_vel - nx3 angular velocity of dumbbell frame wrt to inertial frame expressed in dumbbell frame (rad/sec)

        Outputs:
            T - nx1 kinetic energy array which should be the same length as state input

        """
        # some constants
        m = self.m1 + self.m2  # total mass of dumbbell in kg
        Jd = self.Jd

        KE = np.zeros(time.shape[0])
        PE = np.zeros(time.shape[0])

        for ii in range(time.shape[0]):
            pos = state[
                ii,
                0:3]  # location of the center of mass in the inertial frame
            vel = state[ii, 3:6]  # vel of com in inertial frame
            R = np.reshape(state[ii, 6:15],
                           (3, 3))  # sc body frame to inertial frame
            ang_vel = state[
                ii, 15:
                18]  # angular velocity of sc wrt inertial frame defined in body frame

            Ra = attitude.rot3(ast.omega * time[ii],
                               'c')  # asteroid body frame to inertial frame

            # position of each mass in the inertial frame
            z1 = Ra.T.dot(pos + R.dot(self.zeta1))
            z2 = Ra.T.dot(pos + R.dot(self.zeta2))

            (U1, _, _, _) = ast.polyhedron_potential(z1)
            (U2, _, _, _) = ast.polyhedron_potential(z2)

            PE[ii] = -self.m1 * U1 - self.m2 * U2
            KE[ii] = 1.0 / 2 * m * vel.dot(vel) + 1.0 / 2 * np.trace(
                attitude.hat_map(ang_vel).dot(Jd).dot(
                    attitude.hat_map(ang_vel).T))

        return KE, PE
Example #14
0
def fixed_attitude(time, state):
    """Desired attitude to ensure that the x axis is always pointing at the origin (asteroid)

    """
    # extract out the states
    pos = state[0:3]  # location of the center of mass in the inertial frame
    vel = state[3:6]  # vel of com in inertial frame
    R = np.reshape(state[6:15], (3, 3))  # sc body frame to inertial frame
    ang_vel = state[
        15:
        18]  # angular velocity of sc wrt inertial frame defined in body frame

    Rd = attitude.rot3(np.pi, 'c')
    Rd_dot = np.zeros_like(Rd)
    ang_vel_d = np.zeros(3)
    ang_vel_d_dot = np.zeros(3)

    return (Rd, Rd_dot, ang_vel_d, ang_vel_d_dot)
Example #15
0
def rhoazel(sat_eci, site_eci, site_lat, site_lst):
    """
    This function calculates the topcentric range,azimuth and elevation from
    the site vector and satellite position vector.

    Author:   C2C Shankar Kulumani   USAFA/CS-19   719-333-4741

    Inputs:
        sat_eci - satellite ECI position vector (km)
        site_eci - site ECI position vector (km)
        site_lat - site geodetic latitude (radians)
        site_lst - site local sidereal time (radians)

    Outputs:
        rho - range (km)
        az - asimuth (radians)
        el - elevation (radians)

    Globals: None

    Constants: None

    Coupling: 

    References:
        Astro 321 Predict LSN 22 
    """

    site2sat_eci = sat_eci - site_eci

    site2sat_sez = attitude.rot3(-site_lst).dot(site2sat_eci)
    site2sat_sez = attitude.rot2(-(np.pi / 2 - site_lat)).dot(site2sat_sez)

    rho = np.linalg.norm(site2sat_sez)
    el = np.arcsin(site2sat_sez[2] / rho)
    az = attitude.normalize(np.arctan2(site2sat_sez[1], -site2sat_sez[0]), 0,
                            2 * np.pi)[0]

    return rho, az, el
Example #16
0
def rhoazel(sat_eci, site_eci, site_lat, site_lst):
    """
    This function calculates the topcentric range,azimuth and elevation from
    the site vector and satellite position vector.

    Author:   C2C Shankar Kulumani   USAFA/CS-19   719-333-4741

    Inputs:
        sat_eci - satellite ECI position vector (km)
        site_eci - site ECI position vector (km)
        site_lat - site geodetic latitude (radians)
        site_lst - site local sidereal time (radians)

    Outputs:
        rho - range (km)
        az - asimuth (radians)
        el - elevation (radians)

    Globals: None

    Constants: None

    Coupling: 

    References:
        Astro 321 Predict LSN 22 
    """

    site2sat_eci = sat_eci - site_eci

    site2sat_sez = attitude.rot3(-site_lst).dot(site2sat_eci)
    site2sat_sez = attitude.rot2(-(np.pi / 2 - site_lat)).dot(site2sat_sez)

    rho = np.linalg.norm(site2sat_sez)
    el = np.arcsin(site2sat_sez[2] / rho)
    az = attitude.normalize(np.arctan2(site2sat_sez[1], -site2sat_sez[0]), 0,
                            2 * np.pi)[0]

    return rho, az, el
Example #17
0
class TestHamiltonRelativeTransform():

    time = np.array([0])
    ast = asteroid.Asteroid(name='castalia', num_faces=64)
    dum = dumbbell.Dumbbell()

    inertial_pos = np.array([1, 1, 1])
    inertial_vel = np.random.rand(3) + att.hat_map(
        ast.omega * np.array([0, 0, 1])).dot(inertial_pos)
    R_sc2int = att.rot2(np.pi / 2)
    R_ast2int = att.rot3(time * ast.omega)
    body_ang_vel = np.random.rand(3)

    initial_lin_mom = (dum.m1 + dum.m2) * (inertial_vel)
    initial_ang_mom = R_sc2int.dot(dum.J).dot(body_ang_vel)
    initial_ham_state = np.hstack(
        (inertial_pos, initial_lin_mom, R_ast2int.dot(R_sc2int).reshape(9),
         initial_ang_mom))

    inertial_state = transform.eoms_hamilton_relative_to_inertial(
        time, initial_ham_state, ast, dum)

    def test_eoms_hamilton_relative_to_inertial_scalar_pos(self):
        np.testing.assert_almost_equal(self.inertial_pos,
                                       self.inertial_state[0:3])

    def test_eoms_hamilton_relative_to_inertial_scalar_vel(self):
        np.testing.assert_almost_equal(self.inertial_vel,
                                       self.inertial_state[3:6])

    def test_eoms_hamilton_relative_to_inertial_scalar_att(self):
        np.testing.assert_almost_equal(self.R_sc2int.reshape(9),
                                       self.inertial_state[6:15])

    def test_eoms_hamilton_relative_to_inertial_scalar_ang_vel(self):
        np.testing.assert_almost_equal(self.R_sc2int.dot(self.body_ang_vel),
                                       self.inertial_state[15:18])
Example #18
0
def linear_x_descent_translation(time,
                                 ast,
                                 final_pos=[0.550, 0, 0],
                                 initial_pos=[2.550, 0, 0],
                                 descent_tf=3600):
    """Desired translational states for vertical landing on asteroid
    
    Inputs :
    --------
    
    """
    # rotation state of the asteroid - assume all simulations start with asteroid aligned with the inertial frame
    omega_ast = ast.omega
    omega_ast_dot = 0

    omega_ast_vec = np.array([0, 0, omega_ast])
    omega_ast_dot_vec = np.zeros(3)

    Ra2i = attitude.rot3(omega_ast * time, 'c')
    # determine desired position and velocity in the body fixed frame at this current time input
    # we'll use a simple linear interpolation between initial and final states
    xslope = (final_pos[0] - initial_pos[0]) / (descent_tf)
    xdes = xslope * time + initial_pos[0]

    body_pos_des = np.array([xdes, 0, 0])
    body_vel_des = np.array([xslope, 0, 0])
    body_acc_des = np.zeros(3)
    # transform this body position/velocity into the inertial frame
    inertial_pos = Ra2i.dot(body_pos_des)
    inertial_vel = body_vel_des + np.cross(omega_ast_vec, body_pos_des)
    inertial_accel = body_acc_des + 2 * np.cross(
        omega_ast_vec, body_vel_des) + np.cross(
            omega_ast_vec, np.cross(omega_ast_vec, body_pos_des))

    # output
    return inertial_pos, inertial_vel, inertial_accel
Example #19
0
def plot_keyframe_original(time, i_state, R_ast2int, R_bcam2i, save_fig=False,
                             fwidth=1, filename='/tmp/estimate.eps',
                             kf_path='./data/itokawa_landing/cycles_high_7200_keyframe_poses_remove_first_kf.txt'):
    """Plot keyframe trajectory without any transformation
    """
    # convert inertial position into asteriod fixed frame
    inertial_pos = i_state[:, 0:3]
    asteroid_pos = np.zeros_like(inertial_pos)

    for ii, (ip, Ra2i) in enumerate(zip(inertial_pos, R_ast2int)):
        asteroid_pos[ii, :] = Ra2i.reshape((3,3)).T.dot(ip)

    # first determine the scale of the keyframe translations
    kf_data = np.loadtxt(kf_path)
    kf_time = kf_data[:, 0].astype(dtype='int') # time of keyframe, matches image/time vector
    kf_traj = kf_data[:, 1:4] # postiion of each frame relative to the first
    kf_quat = kf_data[:, 4:8] # rotation from first keyframe to current
    
    Rcam2ast = attitude.rot3(np.deg2rad(-60)).dot(np.array([[1, 0, 0],
                         [0, 0, 1],
                         [0, 1, 0]]))

    kf_traj = Rcam2ast.dot(kf_traj.T).T
    
    # need R at time of first frame and then the asteroid to inertial - dumbbell to ast needed
    R0_s2i = i_state[653, 6:15].reshape((3, 3))
    R0_a2i = R_ast2int[653, :].reshape((3, 3))

    R0_s2a = (R0_a2i.T.dot(R0_s2i))
    
    kf_traj = R0_s2a.dot(kf_traj.T).T

    kf_R_first2cur = np.zeros((len(kf_time), 9))
    # transform each quaternion to a rotation matrix
    for ii,q in enumerate(kf_quat):
        kf_R_first2cur[ii, :] = R0_s2a.dot(Rcam2ast.dot(attitude.quattodcm(q))).reshape(-1)

    # rotate each keyframe point by the corresponding angle of asteroid
    # for ii,index in enumerate(kf_time):
        # kf_traj[ii,:] = R_ast2int[ii,:].reshape((3,3)).T.dot(kf_traj[ii,:])
        # kf_R_first2cur[ii, :] = R_ast2int[ii, :].reshape((3, 3)).T.dot(kf_R_first2cur[ii, :].reshape((3,3))).reshape(-1)

    # determine scale of translation between keyframe points
    kf_diff = np.diff(kf_traj, axis=0)
    kf_scale = np.sqrt(np.sum(kf_diff ** 2, axis=1))
    
    # find true positions at the same time as keyframes
    kf_traj_true = asteroid_pos[kf_time[0]:kf_time[-1], :]
    kf_scale_true = np.sqrt(np.sum(kf_traj_true ** 2, axis=1))
    scale = kf_scale_true[0]
    Rb2i = R_bcam2i[kf_time[0], :].reshape((3,3))
    Rb2a = R_ast2int[kf_time[0], :].reshape((3, 3)).T.dot(Rb2i)
    
    # scale and translate
    kf_traj = scale * kf_traj + asteroid_pos[kf_time[0], :]
    
    # translate kf_traj
    difference = kf_traj[0, :] - kf_traj_true[0, :]
    kf_traj = kf_traj - difference
    # plot keyframe motion without any modifications
    kf_orig_fig = plt.figure()
    kf_orig_ax = axes3d.Axes3D(kf_orig_fig)
    
    kf_orig_ax.set_zlim3d(-1, 1)
    kf_orig_ax.set_xlim3d(-0, 2)
    kf_orig_ax.set_ylim3d(-1, 1)
    kf_orig_ax.plot(kf_traj[:,0], kf_traj[:, 1], kf_traj[:, 2], 'b-*')


    # plot the viewing direction
    length = 0.3
    for ii, R in enumerate(kf_R_first2cur):
        view_axis = R.reshape((3,3))[:, 2]
        kf_orig_ax.plot([kf_traj[ii, 0], kf_traj[ii, 0] + length * view_axis[0]], 
                        [kf_traj[ii, 1], kf_traj[ii, 1] + length * view_axis[1]],
                        [kf_traj[ii, 2], kf_traj[ii, 2] + length * view_axis[2]],
                        'r')

    kf_orig_ax.plot(kf_traj_true[:, 0], kf_traj_true[:, 1], kf_traj_true[:, 2], 'r')
    kf_orig_ax.set_title('Keyframe Original')
    kf_orig_ax.set_xlabel('X')
    kf_orig_ax.set_ylabel('Y')
    kf_orig_ax.set_zlabel('Z')

    # plot the components
    kf_comp_fig, kf_comp_ax = plt.subplots(3, 1, figsize=plotting.figsize(1), sharex=True)
    kf_comp_ax[0].plot(kf_time, kf_traj[:, 0], 'b-*', label='Estimate')
    kf_comp_ax[0].plot(time[kf_time[0]:kf_time[-1]], kf_traj_true[:, 0], 'r-', label='True')
    kf_comp_ax[0].set_ylim(0, 3)
    kf_comp_ax[0].set_ylabel(r'$X$ (km)')
    kf_comp_ax[0].grid()

    kf_comp_ax[1].plot(kf_time, kf_traj[:, 1], 'b-*', label='Estimate')
    kf_comp_ax[1].plot(time[kf_time[0]:kf_time[-1]], kf_traj_true[:, 1], 'r-', label='True')
    kf_comp_ax[1].set_ylim(-2, 1)
    kf_comp_ax[1].set_ylabel(r'$Y$ (km)')
    kf_comp_ax[1].grid()

    kf_comp_ax[2].plot(kf_time, kf_traj[:, 2], 'b-*', label='Estimate')
    kf_comp_ax[2].plot(time[kf_time[0]:kf_time[-1]], kf_traj_true[:, 2], 'r-', label='True')
    kf_comp_ax[2].set_ylim(-0.5, 2.5)
    kf_comp_ax[2].set_ylabel(r'$Z$ (km)')
    kf_comp_ax[2].grid()

    kf_comp_ax[2].set_xlabel('Time (sec)')
    plt.legend(loc='best')

    if save_fig:
        plt.figure(kf_comp_fig.number)
        plt.savefig(filename)

    plt.show()
Example #20
0
def ast2inertial(time, state, ast, dum):
    """Convert from the asteroid frame to the inertial frame
     
    This will convert a state vector which is defined in the asteroid frame
    into the equivalent representation in the inertial frame. 

    Inputs:
        time - nx1 array of time stamps for the state vector
        state - nx18 array of the state vector defined as follows:
            ast_pos - state[:, 0:3] is the position of the body with respect to the asteroid 
                center and defined in the asteroid frame
            ast_vel - state[:, 4:6] is the velocity of the sc with respect to the asteroid 
                center of mass and defined in the asteroid frame
            R_sc2ast - state[:, 6:15] the rotation matrix which transforms vectors from the sc frame
                to the asteroid frame
            ast_w - state[:, 15:18] the angular velocity of the sc with respect to the inertial
                frame and defined in the asteroid frame
        ast - Instance of Asteroid class
        dum - Instance of Dumbbell class

    Outputs:
        inertial_state - the state as represented in the rotating asteroid fixed frame
            inertial_pos - inertial_state[:, 0:3] is the position of the sc with respect to the asteroid
                fixed frame and represented in the inertial frame
            inertial_vel - inertial_state[:, 3:6] is the velocity of the sc with respect to the asteroid and 
                represented in the inertial fixed frame
            inertial_R_sc2int - inertial_state[:, 6:15] is the transformation from the sc frame to the inertial
                frame
            inertial_w - inertial_state[:, 15:18] is the angular velocity of the sc with respect to the inertial 
                frame and defined in the inertial frame


    """

    # transformation between asteroid fixed frame and inertial frame
    # figure out transformation from inertial frame to relative frame
    Rast2int = np.zeros((3, 3, time.shape[0]))
    Rint2ast = np.zeros((3, 3, time.shape[0]))

    inertial_state = np.zeros(state.shape)

    for ii, t in np.ndenumerate(time):
        Rast2int[:, :, ii] = attitude.rot3(
            ast.omega * t,
            'c')[:, :, np.newaxis]  # asteroid body frame to inertial frame
        Rint2ast[:, :, ii] = attitude.rot3(ast.omega * t, 'c').T[:, :,
                                                                 np.newaxis]

        Ra = np.squeeze(Rast2int[:, :, ii])
        # convert the relative state to the inertial frame
        ast_pos = np.squeeze(state[ii, 0:3])
        ast_vel = np.squeeze(state[ii, 3:6])
        R_sc2ast = np.squeeze(state[ii, 6:15].reshape(3, 3))
        ast_w = np.squeeze(state[ii, 15:18])

        inertial_pos = Ra.dot(ast_pos)
        inertial_vel = Ra.dot(ast_vel)
        inertial_R_sc2int = Ra.dot(R_sc2ast).reshape(9)
        inertial_w = Ra.dot(ast_w)

        inertial_state[ii, :] = np.hstack(
            (inertial_pos, inertial_vel, inertial_R_sc2int, inertial_w))

    return inertial_state, Rast2int, Rint2ast
Example #21
0
def eoms_hamilton_relative_to_asteroid(time, state, ast, dum):
    """Convert eoms_hamilton_relative to the asteroid rotating frame

    This function will convert the output from the eoms_hamilton_relative into the asteroid frame.
    Since the equations are defined in the hamiltonian form first the inverse legendre transform 
    is used followed by a transformation into the asteroid frame. 

    The output of this function along with eoms_inertial_to_asteroid should be in the same frame
    and allows for easy comparison.

    Parameters
    ----------
    time : nx1 numpy array
        time array of the simulation
    state : nx18 numpy array
        pos - state[0:3] in km position of the dumbbell with respect to the asteroid and defined in the asteroid fixed frame
        lin_mom - state[3:6] in kg km/sec is the linear momentum of dumbbell wrt the asteroid and defined in the asteroid fixed frame
        R - state[6:15] rotation matrix which converts vectors from the dumbbell frame to the asteroid frame
        ang_mom - state[15:18] J rad/sec angular momentum of the dumbbell wrt inertial frame and defined in the asteroid frame
    ast - Instance of Asteroid class
    dum - Instance of Dumbbell class
    
    Returns
    -------
    ast_state : nx18 numpy array 
        ast_pos - ast_state[:, 0:3] is the position of the sc with respect to the asteroid
            fixed frame and represented in the asteroid frame
        ast_vel - ast_state[:, 3:6] is the velocity of the sc with respect to the asteroid and 
            represented in the asteroid fixed frame
        ast_R_sc2ast - ast_state[:, 6:15] is the transformation from the sc frame to the asteroid
            frame
        ast_w - ast_state[:, 15:18] is the angular velocity of the sc with respect to the inertial 
            frame and defined in the asteroid frame
    """

    if state.ndim == 1:
        # first do the inverse legendre transform
        rel_lin_mom = state[3:6]
        rel_ang_mom = state[15:18]
        R = state[6:15].reshape((3, 3))

        rh_vel = rel_lin_mom / (dum.m1 + dum.m2)

        Rast2int = attitude.rot3(ast.omega * time, 'c')
        Ra = Rast2int
        Jr = R.dot(dum.J).dot(R.T)

        rh_ang_vel = np.linalg.inv(Jr).dot(rel_ang_mom)

        ast_state = np.hstack((state[0:3], rh_vel, R.reshape(9), rh_ang_vel))
    elif state.ndim == 2:
        rel_lin_mom = state[:, 3:6]
        rel_ang_mom = state[:, 15:18]

        rh_vel = rel_lin_mom / (dum.m1 + dum.m2)
        rh_ang_vel = np.zeros_like(rel_ang_mom)

        Rast2int = np.zeros((3, 3, time.shape[0]))

        ast_state = np.zeros(state.shape)

        for ii, t in np.ndenumerate(time):
            Rast2int[:, :, ii] = attitude.rot3(ast.omega * t, 'c')[:, :,
                                                                   np.newaxis]
            Ra = np.squeeze(Rast2int[:, :, ii])

            R = state[ii, 6:15].reshape((3, 3))

            Jr = R.dot(dum.J).dot(R.T)
            rh_ang_vel[ii, :] = np.linalg.inv(Jr).dot(
                np.squeeze(rel_ang_mom[ii, :]))

            ast_state[ii, :] = np.hstack(
                (state[ii, 0:3], rh_vel[ii, :], R.reshape(
                    (1, 9)), rh_ang_vel[ii, :]))

    return ast_state
Example #22
0
def eoms_inertial_to_asteroid(time, state, ast, dum):
    """Convert eoms_inertial output into the asteroid rotating frame
    
    The eoms_inertial are not completely defined in the inertial frame.
    The angular velocity needs to be converted. This function eases that issue by simply accpeting
    the entire state output from eoms_inertial and transforming it.

    Parameters
    ----------
    time : nx1 numpy array
        time array of the simulation
    state : nx18 numpy array
        pos - state[0:3] in km position of the dumbbell with respect to the asteroid and defined in the asteroid fixed frame
        lin_mom - state[3:6] in kg km/sec is the linear momentum of dumbbell wrt the asteroid and defined in the asteroid fixed frame
        R - state[6:15] rotation matrix which converts vectors from the dumbbell frame to the asteroid frame
        ang_mom - state[15:18] J rad/sec angular momentum of the dumbbell wrt inertial frame and defined in the asteroid frame
    ast : Instance of Asteroid class
    dum : Instance of Dumbbell class
    
    Returns
    -------
    ast_state : nx18 numpy array 
        ast_pos - ast_state[:, 0:3] is the position of the sc with respect to the asteroid
            fixed frame and represented in the asteroid rotating frame
        ast_vel - ast_state[:, 3:6] is the velocity of the sc with respect to the asteroid and 
            represented in the asteroid rotating frame
        ast_R_sc2ast - ast_state[:, 6:15] is the transformation from the sc frame to the inertial
            frame
        ast_w - ast_state[:, 15:18] is the angular velocity of the sc with respect to the inertial 
            frame and defined in the asteroid frame
    """

    ast_state = np.zeros(state.shape)

    if state.ndim == 1:
        inertial_pos = state[0:3]
        inertial_vel = state[3:6]
        R_sc2int = state[6:15]
        body_w = state[15:18]

        Rast2int = attitude.rot3(ast.omega * time,
                                 'c')  # asteroid body frame to inertial frame
        Ra = Rast2int

        ast_pos = Ra.T.dot(inertial_pos)
        ast_vel = Ra.T.dot(inertial_vel)
        R_sc2ast = Ra.T.dot(R_sc2int.reshape((3, 3))).reshape(9)
        ast_w = R_sc2ast.reshape((3, 3)).dot(body_w)

        ast_state = np.hstack((ast_pos, ast_vel, R_sc2ast, ast_w))
    elif state.ndim == 2:

        # transformation between asteroid fixed frame and inertial frame
        # figure out transformation from inertial frame to relative frame
        Rast2int = np.zeros((3, 3, time.shape[0]))

        for ii, t in np.ndenumerate(time):
            Rast2int[:, :, ii] = attitude.rot3(
                ast.omega * t,
                'c')[:, :, np.newaxis]  # asteroid body frame to inertial frame

            Ra = np.squeeze(Rast2int[:, :, ii])
            # convert the relative state to the inertial frame
            inertial_pos = np.squeeze(state[ii, 0:3])
            inertial_vel = np.squeeze(state[ii, 3:6])
            R_sc2int = np.squeeze(state[ii, 6:15].reshape(3, 3))
            body_w = np.squeeze(state[ii, 15:18])

            ast_pos = Ra.T.dot(inertial_pos)
            ast_vel = Ra.T.dot(inertial_vel)
            ast_R_sc2ast = Ra.T.dot(R_sc2int).reshape(9)
            ast_w = ast_R_sc2ast.reshape((3, 3)).dot(body_w)

            ast_state[ii, :] = np.hstack(
                (ast_pos, ast_vel, ast_R_sc2ast, ast_w))

    return ast_state
Example #23
0
def rv2rhoazel(r_sat_eci, v_sat_eci, lat, lon, alt, jd):
    """
    This function calculates the topcentric range,azimuth and elevation from
    the site vector and satellite position vector.

    Author:   C2C Shankar Kulumani   USAFA/CS-19   719-333-4741

    Inputs:
        sat_eci - satellite ECI position vector (km)
        site_eci - site ECI position vector (km)
        site_lat - site geodetic latitude (radians)
        site_lst - site local sidereal time (radians)

    Outputs:
        rho - range (km)
        az - asimuth (radians)
        el - elevation (radians)

    Globals: None

    Constants: None

    Coupling:

    References:
        Astro 321 Predict LSN 22
        Vallado Algorithm 27
    """
    small = constants.small
    halfpi = constants.halfpi

    # get site in ECEF
    r_site_ecef = lla2ecef(lat, lon, alt)

    # convert sat and site to ecef
    dcm_eci2ecef = transform.dcm_eci2ecef(jd)
    omega_earth = np.array([0, 0, constants.earth.omega])

    r_sat_ecef = dcm_eci2ecef.dot(r_sat_eci)
    v_sat_ecef = dcm_eci2ecef.dot(
        v_sat_eci) - np.cross(omega_earth, r_sat_ecef)

    # find relative vector in ecef frame
    rho_ecef = r_sat_ecef - r_site_ecef
    drho_ecef = v_sat_ecef - np.zeros_like(v_sat_ecef)  # site isn't moving
    rho = np.linalg.norm(rho_ecef)

    # convert to SEZ coordinate frame
    dcm_ecef2sez = attitude.rot2(
        np.pi / 2 - lat, 'r').dot(attitude.rot3(lon, 'r'))
    rho_sez = dcm_ecef2sez.dot(rho_ecef)
    drho_sez = dcm_ecef2sez.dot(drho_ecef)

    # find azimuth and eleveation
    temp = np.sqrt(rho_sez[0]**2 + rho_sez[1]**2)

    if temp < small:  # directly over the north pole
        el = np.sign(rho_sez[2]) * halfpi  # \pm 90 deg
    else:
        mag_rho_sez = np.linalg.norm(rho_sez)
        el = np.arcsin(rho_sez[2] / mag_rho_sez)

    if temp < small:
        az = np.arctan2(drho_sez[1], - drho_sez[0])
    else:
        az = np.arctan2(rho_sez[1] / temp, -rho_sez[0] / temp)

    # range, azimuth and elevation rates
    drho = np.dot(rho_sez, drho_sez) / rho

    if np.absolute(temp**2) > small:
        daz = (drho_sez[0] * rho_sez[1] - drho_sez[1] * rho_sez[0]) / temp**2
    else:
        daz = 0

    if np.absolute(temp) > small:
        dele = (drho_sez[2] - drho * np.sin(el)) / temp
    else:
        dele = 0

    az = attitude.normalize(az, 0, constants.twopi)
    return rho, az, el, drho, daz, dele
Example #24
0
v1 = np.linalg.norm(out[8])
fpa1 = out[4]

# compute burn
rf, vf, fpaf = manuever.single_impulse(r1, v1, fpa1, delta_v, alpha)
an, pn, eccn, nun = manuever.rvfpa2orbit_el(rf, vf, fpaf, mu)
delta_arg_p = nuf - nun
print('Orbital Elements after burn')
kepler.orbit_el(pn, eccn, 0, 0, delta_arg_p, nun, mu, True)

# generate a plot of the orbit
_, state_pqw1, _, _, sat_pqw1, _ = kepler.conic_orbit(p, ecc, 0, 0, 0, nuf, nuf, mu)
_, state_pqw2, _, _, sat_pqw2, _ = kepler.conic_orbit(pn, eccn, 0, 0, 0, nun, nun, mu)

# rotate the second orbit by the change in argument of perigee
rot_old2new = attitude.rot3(delta_arg_p)
state_pqw2 = rot_old2new.dot(state_pqw2[:, 0:3].T).T
sat_pqw2 = rot_old2new.dot(sat_pqw2[0:3])
fig, ax = plt.subplots()

ax.plot(state_pqw1[:, 0], state_pqw1[:, 1], label='Initial')
ax.plot(state_pqw2[:, 0], state_pqw2[:, 1], label='Final')

ax.plot([0, sat_pqw2[0]], [0, sat_pqw2[1]], 'b.-', markersize=10)
ax.set_title('Single Impulse Manuever')
ax.set_xlabel(r'$\hat p$')
ax.set_ylabel(r'$\hat q$')
plt.legend()
plt.show()

Example #25
0
def rv2rhoazel(r_sat_eci, v_sat_eci, lat, lon, alt, jd):
    """
    This function calculates the topcentric range,azimuth and elevation from
    the site vector and satellite position vector.

    Author:   C2C Shankar Kulumani   USAFA/CS-19   719-333-4741

    Inputs:
        sat_eci - satellite ECI position vector (km)
        site_eci - site ECI position vector (km)
        site_lat - site geodetic latitude (radians)
        site_lst - site local sidereal time (radians)

    Outputs:
        rho - range (km)
        az - asimuth (radians)
        el - elevation (radians)

    Globals: None

    Constants: None

    Coupling:

    References:
        Astro 321 Predict LSN 22
        Vallado Algorithm 27
    """
    small = constants.small
    halfpi = constants.halfpi

    # get site in ECEF
    r_site_ecef = lla2ecef(lat, lon, alt)

    # convert sat and site to ecef
    dcm_eci2ecef = transform.dcm_eci2ecef(jd)
    omega_earth = np.array([0, 0, constants.earth.omega])

    r_sat_ecef = dcm_eci2ecef.dot(r_sat_eci)
    v_sat_ecef = dcm_eci2ecef.dot(v_sat_eci) - np.cross(
        omega_earth, r_sat_ecef)

    # find relative vector in ecef frame
    rho_ecef = r_sat_ecef - r_site_ecef
    drho_ecef = v_sat_ecef - np.zeros_like(v_sat_ecef)  # site isn't moving
    rho = np.linalg.norm(rho_ecef)

    # convert to SEZ coordinate frame
    dcm_ecef2sez = attitude.rot2(np.pi / 2 - lat,
                                 'r').dot(attitude.rot3(lon, 'r'))
    rho_sez = dcm_ecef2sez.dot(rho_ecef)
    drho_sez = dcm_ecef2sez.dot(drho_ecef)

    # find azimuth and eleveation
    temp = np.sqrt(rho_sez[0]**2 + rho_sez[1]**2)

    if temp < small:  # directly over the north pole
        el = np.sign(rho_sez[2]) * halfpi  # \pm 90 deg
    else:
        mag_rho_sez = np.linalg.norm(rho_sez)
        el = np.arcsin(rho_sez[2] / mag_rho_sez)

    if temp < small:
        az = np.arctan2(drho_sez[1], -drho_sez[0])
    else:
        az = np.arctan2(rho_sez[1] / temp, -rho_sez[0] / temp)

    # range, azimuth and elevation rates
    drho = np.dot(rho_sez, drho_sez) / rho

    if np.absolute(temp**2) > small:
        daz = (drho_sez[0] * rho_sez[1] - drho_sez[1] * rho_sez[0]) / temp**2
    else:
        daz = 0

    if np.absolute(temp) > small:
        dele = (drho_sez[2] - drho * np.sin(el)) / temp
    else:
        dele = 0

    az = attitude.normalize(az, 0, constants.twopi)
    return rho, az, el, drho, daz, dele
Example #26
0
def simulate():

    logger = logging.getLogger(__name__)

    ast, dum, des_att_func, des_tran_func, AbsTol, RelTol = initialize()

    num_steps = int(1e3)
    time = np.linspace(0, num_steps, num_steps)
    t0, tf = time[0], time[-1]
    dt = time[1] - time[0]

    initial_pos = np.array([1.5, 0, 0])
    initial_vel = np.array([0, 0, 0])
    initial_R = attitude.rot3(np.pi / 2).reshape(-1)
    initial_w = np.array([0, 0, 0])
    initial_state = np.hstack((initial_pos, initial_vel, initial_R, initial_w))

    # TODO Initialize a coarse asteroid mesh model and combine with piont cloud data

    # initialize the raycaster and lidar
    polydata = wavefront.meshtopolydata(ast.V, ast.F)
    caster = raycaster.RayCaster(polydata)
    sensor = raycaster.Lidar(dist=5)
    # try both a controlled and uncontrolled simulation
    # t, istate, astate, bstate = eoms.inertial_eoms_driver(initial_state, time, ast, dum)

    # TODO Dynamics should be based on the course model
    # TODO Asteroid class will need a method to update mesh
    system = integrate.ode(eoms.eoms_controlled_inertial)
    system.set_integrator('lsoda', atol=AbsTol, rtol=RelTol, nsteps=1e4)
    system.set_initial_value(initial_state, t0)
    system.set_f_params(ast, dum, des_att_func, des_tran_func)

    point_cloud = defaultdict(list)

    state = np.zeros((num_steps + 1, 18))
    t = np.zeros(num_steps + 1)
    int_array = []
    state[0, :] = initial_state

    ii = 1
    while system.successful() and system.t < tf:

        # integrate the system and save state to an array
        t[ii] = (system.t + dt)
        state[ii, :] = system.integrate(system.t + dt)

        logger.info('Step : {} Time: {}'.format(ii, t[ii]))
        # now do the raycasting
        if not (np.floor(t[ii]) % 1):
            logger.info('Raycasting at t = {}'.format(t[ii]))

            targets = sensor.define_targets(state[ii, 0:3],
                                            state[ii, 6:15].reshape((3, 3)),
                                            np.linalg.norm(state[ii, 0:3]))

            # new asteroid rotation with vertices
            nv = ast.rotate_vertices(t[ii])
            Ra = ast.rot_ast2int(t[ii])
            # update the mesh inside the caster
            caster = raycaster.RayCaster.updatemesh(nv, ast.F)

            # these intersections are points in the inertial frame
            intersections = caster.castarray(state[ii, 0:3], targets)

            point_cloud['time'].append(t[ii])
            point_cloud['ast_state'].append(Ra.reshape(-1))
            point_cloud['sc_state'].append(state[ii, :])
            point_cloud['targets'].append(targets)
            point_cloud['inertial_ints'].append(intersections)

            logger.info('Found {} intersections'.format(len(intersections)))

            ast_ints = []
            for pt in intersections:
                if pt.size > 0:
                    pt_ast = Ra.T.dot(pt)
                else:
                    logger.info('No intersection for this point')
                    pt_ast = np.array([np.nan, np.nan, np.nan])

                ast_ints.append(pt_ast)

            point_cloud['ast_ints'].append(np.asarray(ast_ints))

        # TODO Eventually call the surface reconstruction function and update asteroid model

        # create an asteroid and dumbbell
        ii += 1

    # plot the simulation
    # plotting.animate_inertial_trajectory(t, istate, ast, dum)
    # plotting.plot_controlled_inertial(t, istate, ast, dum, fwidth=1)

    return time, state, point_cloud
Example #27
0
def dcm_pqw2lvlh(nu):
    dcm = attitude.rot3(-nu)
    return dcm
Example #28
0
import pdb

from lib import mesh_data, cgal

filename = './data/shape_model/CASTALIA/castalia.obj'
polydata = wavefront.read_obj_to_polydata(filename)

caster_obb = raycaster.RayCaster(polydata, flag='obb')
caster_bsp = raycaster.RayCaster(polydata, flag='bsp')

sensor = raycaster.Lidar(view_axis=np.array([1, 0, 0]), num_step=3)

# need to translate the sensor and give it a pointing direction
pos = np.array([2, 0, 0])
dist = 2  # distance for each raycast
R = attitude.rot3(np.pi)

# find the inersections
# targets = pos + sensor.rotate_fov(R) * dist
targets = sensor.define_targets(pos, R, dist)
intersections_obb = caster_obb.castarray(pos, targets)
intersections_bsp = caster_bsp.castarray(pos, targets)

# plot
fig = graphics.mayavi_figure(bg=(0, 0, 0))
graphics.mayavi_addPoly(fig, polydata)

graphics.mayavi_addPoint(fig, pos, radius=0.05)

# draw lines from pos to all targets
for pt in targets:
Example #29
0
def eoms_controlled_blender(t, state, dum, ast):
    """Inertial dumbbell equations of motion about an asteroid 
    
    This method must be used with the scipy.integrate.ode class instead of the
    more convienent scipy.integrate.odeint. In addition, we can control the
    dumbbell given full state feedback. Blender is used to generate imagery
    during the simulation.

    Inputs:
        t - Current simulation time step
        state - (18,) array which defines the state of the vehicle 
            pos - (3,) position of the dumbbell with respect to the
            asteroid center of mass and expressed in the inertial frame
            vel - (3,) velocity of the dumbbell with respect to the
            asteroid center of mass and expressed in the inertial frame
            R - (9,) attitude of the dumbbell with defines the
            transformation of a vector in the dumbbell frame to the
            inertial frame ang_vel - (3,) angular velocity of the dumbbell
            with respect to the inertial frame and represented in the
            dumbbell frame
        ast - Asteroid class object holding the asteroid gravitational
        model and other useful parameters
    """
    # unpack the state
    pos = state[0:3]  # location of the center of mass in the inertial frame
    vel = state[3:6]  # vel of com in inertial frame
    R = np.reshape(state[6:15], (3, 3))  # sc body frame to inertial frame
    ang_vel = state[
        15:
        18]  # angular velocity of sc wrt inertial frame defined in body frame

    Ra = attitude.rot3(ast.omega * t,
                       'c')  # asteroid body frame to inertial frame

    # unpack parameters for the dumbbell
    J = dum.J

    rho1 = dum.zeta1
    rho2 = dum.zeta2

    # position of each mass in the asteroid frame
    z1 = Ra.T.dot(pos + R.dot(rho1))
    z2 = Ra.T.dot(pos + R.dot(rho2))

    z = Ra.T.dot(pos)  # position of COM in asteroid frame

    # compute the potential at this state
    (U1, U1_grad, U1_grad_mat, U1laplace) = ast.polyhedron_potential(z1)
    (U2, U2_grad, U2_grad_mat, U2laplace) = ast.polyhedron_potential(z2)

    F1 = dum.m1 * Ra.dot(U1_grad)
    F2 = dum.m2 * Ra.dot(U2_grad)

    M1 = dum.m1 * attitude.hat_map(rho1).dot(R.T.dot(Ra).dot(U1_grad))
    M2 = dum.m2 * attitude.hat_map(rho2).dot(R.T.dot(Ra).dot(U2_grad))

    # generate image at this current state only at a specifc time
    # blender.driver(pos, R, ast.omega * t, [5, 0, 1], 'test' + str.zfill(str(t), 4))
    # use the imagery to figure out motion and pass to the controller instead
    # of the true state

    # calculate the desired attitude and translational trajectory
    des_att_tuple = controller.body_fixed_pointing_attitude(t, state)
    des_tran_tuple = controller.traverse_then_land_vertically(
        t,
        ast,
        final_pos=[0.550, 0, 0],
        initial_pos=[2.550, 0, 0],
        descent_tf=3600)
    # input trajectory and compute the control inputs
    # compute the control input
    u_m = controller.attitude_controller(t, state, M1 + M2, dum, ast,
                                         des_att_tuple)
    u_f = controller.translation_controller(t, state, F1 + F2, dum, ast,
                                            des_tran_tuple)

    pos_dot = vel
    vel_dot = 1 / (dum.m1 + dum.m2) * (F1 + F2 + u_f)
    R_dot = R.dot(attitude.hat_map(ang_vel)).reshape(9)
    ang_vel_dot = np.linalg.inv(J).dot(-np.cross(ang_vel, J.dot(ang_vel)) +
                                       M1 + M2 + u_m)

    statedot = np.hstack((pos_dot, vel_dot, R_dot, ang_vel_dot))

    return statedot
 def test_expm_rot3_equivalent(self):
     R = scipy.linalg.expm(self.angle *
                           attitude.hat_map(np.array([0, 0, 1])))
     R3 = attitude.rot3(self.angle)
     np.testing.assert_almost_equal(R.T.dot(R3), np.eye(3, 3))
Example #31
0
def inertial_asteroid_trajectory(time, state, ast, dum, point_cloud,
                                 mayavi_objects):
    """Animate the rotation of an asteroid and the motion of SC
    """
    mesh, ast_axes, com, dum_axes, pc_lines = mayavi_objects

    # animate the rotation fo the asteroid
    ms = mesh.mlab_source
    ts = com.mlab_source

    ast_xs = ast_axes[0].mlab_source
    ast_ys = ast_axes[1].mlab_source
    ast_zs = ast_axes[2].mlab_source

    dum_xs = dum_axes[0].mlab_source
    dum_ys = dum_axes[1].mlab_source
    dum_zs = dum_axes[2].mlab_source

    pc_sources = [line.mlab_source for line in pc_lines]

    for (t, pos, Rb2i, intersections) in zip(time, state[:, 0:3], state[:,
                                                                        6:15],
                                             point_cloud['inertial_ints']):
        # rotate teh asteroid
        Ra = attitude.rot3(ast.omega * t, 'c')
        Rb2i = Rb2i.reshape((3, 3))
        # parse out the vertices x, y, z
        new_vertices = ast.rotate_vertices(t)

        # update asteroid
        ms.set(x=new_vertices[:, 0],
               y=new_vertices[:, 1],
               z=new_vertices[:, 2])
        # update the satellite
        ts.set(x=pos[0], y=pos[1], z=pos[2])

        # update the asteroid axes
        ast_xs.reset(x=[0, Ra[0, 0]], y=[0, Ra[1, 0]], z=[0, Ra[2, 0]])
        ast_ys.reset(x=[0, Ra[0, 1]], y=[0, Ra[1, 1]], z=[0, Ra[2, 1]])
        ast_zs.reset(x=[0, Ra[0, 2]], y=[0, Ra[1, 2]], z=[0, Ra[2, 2]])

        dum_xs.reset(x=[pos[0], pos[0] + Rb2i[0, 0]],
                     y=[pos[1], pos[1] + Rb2i[1, 0]],
                     z=[pos[2], pos[2] + Rb2i[2, 0]])
        dum_ys.reset(x=[pos[0], pos[0] + Rb2i[0, 1]],
                     y=[pos[1], pos[1] + Rb2i[1, 1]],
                     z=[pos[2], pos[2] + Rb2i[2, 1]])
        dum_zs.reset(x=[pos[0], pos[0] + Rb2i[0, 2]],
                     y=[pos[1], pos[1] + Rb2i[1, 2]],
                     z=[pos[2], pos[2] + Rb2i[2, 2]])

        for pcs, inter in zip(pc_sources, intersections):
            # check if intersection is empty
            if inter.size > 2:
                pcs.reset(x=[pos[0], inter[0]],
                          y=[pos[1], inter[1]],
                          z=[pos[2], inter[2]])
            else:
                pcs.reset(x=[pos[0], pos[0] + 0.01],
                          y=[pos[1], pos[1] + 0.01],
                          z=[pos[2], pos[2] + 0.01])
        yield
Example #32
0
def dcm_ecef2sez(latgd, lon, alt=0):
    # dcm = attitude.rot2(np.pi/2 - latgd, 'r').dot(attitude.rot3(lon, 'r'))
    dcm = attitude.rot2(latgd - np.pi/2).dot(attitude.rot3(-lon))
    return dcm
Example #33
0
def test_rotation():
    R = attitude.rot3(np.pi / 2)
    sensor_x = raycaster.Lidar()
    rot_arr = raycaster.Lidar().rotate_fov(R)
    np.testing.assert_array_almost_equal(rot_arr,
                                         R.dot(sensor_x.lidar_arr.T).T)
Example #34
0
 def test_rot3_orthogonal_row(self):
     mat = attitude.rot3(self.angle, 'r')
     np.testing.assert_array_almost_equal(mat.T.dot(mat), np.eye(3, 3))
Example #35
0
 def test_rot3_determinant_1_row(self):
     mat = attitude.rot3(self.angle, 'r')
     np.testing.assert_allclose(np.linalg.det(mat), 1)
Example #36
0
def blender_asteroid_frame_sim(gen_images=False):
    # simulation parameters
    output_path = './visualization/blender'
    asteroid_name = 'itokawa_low'
    # create a HDF5 dataset
    hdf5_path = './data/asteroid_circumnavigate/{}_asteroid_circumnavigate.hdf5'.format(
        datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S"))
    dataset_name = 'landing'
    render = 'BLENDER'
    image_modulus = 1
    RelTol = 1e-6
    AbsTol = 1e-6
    ast_name = 'itokawa'
    num_faces = 64
    t0 = 0
    dt = 1
    tf = 3600 * 1
    num_steps = 3600 * 1

    ast = asteroid.Asteroid(ast_name,num_faces)
    dum = dumbbell.Dumbbell(m1=500, m2=500, l=0.003)

    # instantiate the blender scene once
    camera_obj, camera, lamp_obj, lamp, itokawa_obj, scene = blender.blender_init(render_engine=render, asteroid_name=asteroid_name)

    # get some of the camera parameters
    K = blender_camera.get_calibration_matrix_K_from_blender(camera)

    periodic_pos = np.array([1.495746722510590,0.000001002669660,0.006129720493607])
    periodic_vel = np.array([0.000000302161724,-0.000899607989820,-0.000000013286327])

    # set initial state for inertial EOMs
    # initial_pos = np.array([2.550, 0, 0]) # km for center of mass in body frame
    initial_pos = np.array([3, 0, 0])
    initial_vel = periodic_vel + attitude.hat_map(ast.omega*np.array([0,0,1])).dot(initial_pos)
    initial_R = attitude.rot3(np.pi/2).reshape(9) # transforms from dumbbell body frame to the inertial frame
    initial_w = np.array([0.01, 0.01, 0.01])
    initial_state = np.hstack((initial_pos, initial_vel, initial_R, initial_w))

    # instantiate ode object
    # system = integrate.ode(eoms_controlled_blender)
    system = integrate.ode(eoms.eoms_controlled_relative_blender_ode)
    system.set_integrator('lsoda', atol=AbsTol, rtol=RelTol, nsteps=1000)
    system.set_initial_value(initial_state, t0)
    system.set_f_params(dum, ast)

    i_state = np.zeros((num_steps+1, 18))
    time = np.zeros(num_steps+1)
    i_state[0, :] = initial_state

    with h5py.File(hdf5_path) as image_data:
        # create a dataset
        if gen_images:
            images = image_data.create_dataset(dataset_name, (244, 537, 3,
                                                              num_steps/image_modulus),
                                               dtype='uint8')
            RT_blender = image_data.create_dataset('RT',
                                                   (num_steps/image_modulus,
                                                    12)) 
            R_i2bcam = image_data.create_dataset('R_i2bcam',
                                                 (num_steps/image_modulus, 9))
       
        ii = 1
        while system.successful() and system.t < tf:
            # integrate the system and save state to an array
            time[ii] = (system.t + dt)
            i_state[ii, :] = (system.integrate(system.t + dt))
            # generate the view of the asteroid at this state
            if int(time[ii]) % image_modulus== 0 and gen_images:
                img, RT, R = blender.gen_image_fixed_ast(i_state[ii,0:3], 
                                                         i_state[ii,6:15].reshape((3,3)),
                                                         ast.omega * (time[ii] - 3600),
                                                         camera_obj, camera,
                                                         lamp_obj, lamp,
                                                         itokawa_obj, scene,
                                                         [5, 0, 1], 'test')

                images[:, :, :, ii//image_modulus - 1] = img
                RT_blender[ii//image_modulus -1, :] = RT.reshape(12)
                R_i2bcam[ii//image_modulus -1, :] = R.reshape(9)


            # do some image processing and visual odometry
            print(system.t)
            ii += 1

        image_data.create_dataset('K', data=K)
        image_data.create_dataset('i_state', data=i_state)
        image_data.create_dataset('time', data=time)
Example #37
0
def test_view_axis():
    sensor_y = raycaster.Lidar(view_axis=np.array([0, 1, 0]))
    sensor_x = raycaster.Lidar()
    R = attitude.rot3(np.pi / 2)
    np.testing.assert_array_almost_equal(sensor_y.lidar_arr,
                                         R.dot(sensor_x.lidar_arr.T).T)