Esempio n. 1
0
def ecef2ned(gps,refLla):
	ecefOrigin1D = navpy.lla2ecef(refLla.lat,refLla.lon,refLla.alt)
	ecefOrigin = np.array([ecefOrigin1D]).T
	ecefPositionLocal = gps.position - ecefOrigin
	gpsPositionNed = navpy.ecef2ned(ecefPositionLocal,refLla.lat,refLla.lon,refLla.alt)
	gpsVelocityNed = navpy.ecef2ned(gps.velocity,refLla.lat,refLla.lon,refLla.alt)
	gpsNed = GpsNed(gps.time,gpsPositionNed,gpsVelocityNed)
	return gpsNed
    def base_gps_callback(self, gps):
        if gps.fix != 3:
            print('base gps not in fix.  Fix = ', gps.fix)
            return
        if not self.refLlaSet:
            return
        velocityNed1D = navpy.ecef2ned(gps.velocityEcef, self.latRef,
                                       self.lonRef, self.altRef)
        velocityNed = np.array([velocityNed1D]).T

        zt = velocityNed
        ht = ekf.update_base_gps_velocity_model(self.baseStates.euler,
                                                self.belief.vb,
                                                self.baseStates.wLpf,
                                                self.params.antennaOffset)
        Ct = ekf.get_jacobian_C_base_velocity(self.baseStates)

        ekf.update(self.belief, self.params.QtGpsVelocity, zt, ht, Ct)
Esempio n. 3
0
    def test_ecef2ned(self):
        """
        Test conversion from ECEF to NED.
        
        Data Source: Examples 2.1 and 2.4 of Aided Navigation: GPS with High
                     Rate Sensors, Jay A. Farrel 2008
        Note: N, E (+) and S, W (-)
        """
        # A point near Los Angeles, CA, given from equation 2.12 [degrees]
        lat = +( 34. +  0./60 + 0.00174/3600) # North
        lon = -(117. + 20./60 + 0.84965/3600) # West
        alt = 251.702 # [meters]

        # Define example ECEF vector and associated NED, given in Example 2.4
        ecef = np.array([0.3808, 0.7364, -0.5592])
        ned  = np.array([0, 0, 1]) # local unit gravity
        
        # Do conversion and check result
        # Note: default assumption on units is deg and meters
        ned_computed = navpy.ecef2ned(ecef, lat, lon, alt) 
        
        for e1, e2 in zip(ned_computed, ned):
            self.assertAlmostEqual(e1, e2, places=3)
Esempio n. 4
0
    def test_ecef2ned(self):
        """
        Test conversion from ECEF to NED.
        
        Data Source: Examples 2.1 and 2.4 of Aided Navigation: GPS with High
                     Rate Sensors, Jay A. Farrel 2008
        Note: N, E (+) and S, W (-)
        """
        # A point near Los Angeles, CA, given from equation 2.12 [degrees]
        lat = +(34. + 0. / 60 + 0.00174 / 3600)  # North
        lon = -(117. + 20. / 60 + 0.84965 / 3600)  # West
        alt = 251.702  # [meters]

        # Define example ECEF vector and associated NED, given in Example 2.4
        ecef = np.array([0.3808, 0.7364, -0.5592])
        ned = np.array([0, 0, 1])  # local unit gravity

        # Do conversion and check result
        # Note: default assumption on units is deg and meters
        ned_computed = navpy.ecef2ned(ecef, lat, lon, alt)

        for e1, e2 in zip(ned_computed, ned):
            self.assertAlmostEqual(e1, e2, places=3)
    def rover_gps_callback(self, gps):
        if gps.fix != 3:
            print('rover gps not in fix.  Fix = ', gps.fix)
            return
        if not self.refLlaSet:
            self.latRef = gps.lla[0]
            self.lonRef = gps.lla[1]
            self.altRef = gps.lla[2]
            refEcef1D = navpy.lla2ecef(self.latRef, self.lonRef, self.altRef)
            self.refEcef = np.array([refEcef1D]).T
            self.refLlaSet = True
            print('ref lla = ', self.latRef, ' ', self.lonRef, ' ',
                  self.altRef)

        velocityNed1D = navpy.ecef2ned(gps.velocityEcef, self.latRef,
                                       self.lonRef, self.altRef)
        velocityNed = np.array([velocityNed1D]).T

        zt = velocityNed
        ht = ekf.update_rover_gps_velocity_model(self.belief.vr)
        Ct = ekf.get_jacobian_C_rover_velocity()

        ekf.update(self.belief, self.params.QtGpsVelocity, zt, ht, Ct)
Esempio n. 6
0
def load(flight_dir):
    result = {}

    gps_data = []
    filter_data = []

    # load imu/gps data files
    imu_file = flight_dir + "/imu.csv"
    gps_file = flight_dir + "/gps.csv"
    filter_post = flight_dir + "/filter-post-ins.txt"

    # calibration by plotting and eye-balling (just finding center point, no
    # normalization cooked into calibration.)
    #hx_coeffs = np.array([ 1.0,  -1.5], dtype=np.float64)
    #hy_coeffs = np.array([ 1.0, -78.5], dtype=np.float64)
    #hz_coeffs = np.array([ 1.0, -156.5], dtype=np.float64)

    #~/Projects/PILLS/Phantom\ 3\ Flight\ Data/2016-03-22\ --\ imagery_0012\ -\ 400\ ft\ survey
    #hx_coeffs = np.array([ 0.01857771, -0.18006661], dtype=np.float64)
    #hy_coeffs = np.array([ 0.01856938, -1.20854406], dtype=np.float64)
    #hz_coeffs = np.array([ 0.01559645,  2.81011976], dtype=np.float64)

    # ~/Projects/PILLS/Phantom\ 3\ Flight\ Data/imagery_0009 - 0012
    #hx_coeffs = np.array([ 0.01789447,  3.70605872], dtype=np.float64)
    #hy_coeffs = np.array([ 0.017071,    0.7125617], dtype=np.float64)
    #hz_coeffs = np.array([ 0.01447557, -6.54621951], dtype=np.float64)

    # ~/Projects/PILLS/2016-04-04\ --\ imagery_0002
    # ~/Projects/PILLS/2016-04-14\ --\ imagery_0003
    # ~/Projects/PILLS/2016-04-14\ --\ imagery_0004
    #hx_coeffs = np.array([ 0.01658555, -0.07790598], dtype=np.float64)
    #hy_coeffs = np.array([ 0.01880532, -1.26548151], dtype=np.float64)
    #hz_coeffs = np.array([ 0.01339084,  2.61905809], dtype=np.float64)

    # ~/Projects/PILLS/2016-05-12\ --\ imagery_0004
    #hx_coeffs = np.array([ 0.01925678,  0.01527908], dtype=np.float64)
    #hy_coeffs = np.array([ 0.01890112, -1.18040666], dtype=np.float64)
    #hz_coeffs = np.array([ 0.01645011,  2.87769626], dtype=np.float64)

    #hx_func = np.poly1d(hx_coeffs)
    #hy_func = np.poly1d(hy_coeffs)
    #hz_func = np.poly1d(hz_coeffs)

    # ~/Projects/PILLS/2016-06-29\ --\ calibration_0002/
    # mag_affine = np.array(
    #     [[ 0.0223062041, -0.0002700799, -0.0001325525,  1.2016235718],
    #      [-0.0002700799,  0.0229484854,  0.0000356172,  0.1177744077],
    #      [-0.0001325525,  0.0000356172,  0.0206129279, -3.2713740483],
    #      [ 0.          ,  0.          ,  0.          ,  1.          ]]
    # )

    # Phantom 3 - Aug 2016 (ellipse cal)
    # mag_affine = np.array(
    #     [[ 0.0189725067,  0.0000203615,  0.0002139272, -0.0134053645],
    #      [ 0.0000760692,  0.0180178765,  0.0000389461, -1.044762755 ],
    #      [ 0.0002417847,  0.0000458039,  0.0171450614,  2.647911793 ],
    #      [ 0.          ,  0.          ,  0.          ,  1.          ]]
    # )
    # Phantom 3 - Aug 2016 (ekf cal)
    # mag_affine = np.array(
    #     [[ 0.0181297161,  0.000774339,  -0.002037224 , -0.2576406372],
    #      [ 0.0002434548,  0.018469032,   0.0016475328, -0.8452362072],
    #      [ 0.0000145964,  0.000267444,   0.0159433791,  2.5630653789],
    #      [ 0.          ,  0.         ,   0.          ,  1.          ]]
    # )

    # 2017-06-07_23-43-50
    mag_affine = np.array(
        [[0.0182094965, 0.0001891445, 0.0005079058, -1.0275778093],
         [0.0001891445, 0.0188836673, 0.0003014306, -0.7472003813],
         [0.0005079058, 0.0003014306, 0.0176589615, 0.9988130618],
         [0., 0., 0., 1.]])
    print(mag_affine)

    result['imu'] = []
    fimu = fileinput.input(imu_file)
    for line in fimu:
        #print line
        if not re.search('Time', line):
            tokens = line.split(',')
            #print len(tokens)
            if len(tokens) == 11 and isFloat(tokens[10]):
                #print '"' + tokens[10] + '"'
                (time, p, q, r, ax, ay, az, hx, hy, hz, temp) = tokens
                # remap axis before applying mag calibration
                p = -float(p)
                q = float(q)
                r = -float(r)
                ax = -float(ax) * g
                ay = float(ay) * g
                az = -float(az) * g
                hx = -float(hx)
                hy = float(hy)
                hz = -float(hz)
                mag_orientation = 'random1'
                if mag_orientation == 'older':
                    #hx_new = hx_func(float(hx))
                    #hy_new = hy_func(float(hy))
                    #hz_new = hz_func(float(hz))
                    s = [hx, hy, hz]
                elif mag_orientation == 'newer':
                    # remap for 2016-05-12 (0004) data set
                    #hx_new = hx_func(float(-hy))
                    #hy_new = hy_func(float(-hx))
                    #hz_new = hz_func(float(-hz))
                    s = [-hy, -hx, -hz]
                elif mag_orientation == 'random1':
                    # remap for 2016-05-12 (0004) data set
                    #hx_new = hx_func(float(-hy))
                    #hy_new = hy_func(float(-hx))
                    #hz_new = hz_func(float(-hz))
                    s = [-hy, -hx, hz]
                # mag calibration mapping via mag_affine matrix
                hs = np.hstack([s, 1.0])
                hf = np.dot(mag_affine, hs)
                #print hf[:3]
                #norm = np.linalg.norm([hx_new, hy_new, hz_new])
                #hx_new /= norm
                #hy_new /= norm
                #hz_new /= norm

                imu = Record()
                imu.time = float(time) / 1000000.0
                imu.p = p
                imu.q = q
                imu.r = r
                imu.ax = ax
                imu.ay = ay
                imu.az = az
                do_mag_transform = True
                if do_mag_transform:
                    imu.hx = hf[0]
                    imu.hy = hf[1]
                    imu.hz = hf[2]
                else:
                    imu.hx = s[0]
                    imu.hy = s[1]
                    imu.hz = s[2]
                #float(hf[0]), float(hf[1]), float(hf[2]),
                imu.temp = float(temp)
                result['imu'].append(imu)

    result['gps'] = []
    fgps = fileinput.input(gps_file)
    for line in fgps:
        if not re.search('Timestamp', line):
            # print line
            tokens = line.split(',')
            # print 'gps tokens:', len(tokens)
            if len(tokens) == 14:
                (time, itow, ecefx, ecefy, ecefz, ecefvx, ecefvy, ecefvz,
                 fixtype, posacc, spdacc, posdop, numsvs, flags) = tokens
            elif len(tokens) == 19:
                (time, itow, lat, lon, alt, ecefx, ecefy, ecefz, ecefvx,
                 ecefvy, ecefvz, fixtype, posacc, spdacc, posdop, numsvs,
                 flags, diff_status, carrier_status) = tokens

            # wgs84 position
            pos_source = 'llh'  # 'llh' or 'ecef'
            llh = navpy.ecef2lla([
                float(ecefx) / 100.0,
                float(ecefy) / 100.0,
                float(ecefz) / 100.0
            ], "deg")
            # velocity
            ned = navpy.ecef2ned([
                float(ecefvx) / 100.0,
                float(ecefvy) / 100.0,
                float(ecefvz) / 100.0
            ], llh[0], llh[1], llh[2])
            if int(numsvs) >= 4:
                gps = Record()
                gps.time = float(time) / 1000000.0
                #gps.status = int(status)
                gps.unix_sec = float(time) / 1000000.0  # make filter happy
                gps.lat = float(lat)
                gps.lon = float(lon)
                gps.alt = float(alt)
                gps.vn = ned[0]
                gps.ve = ned[1]
                gps.vd = ned[2]
                result['gps'].append(gps)

    result['filter'] = []
    # load filter (post process) records if they exist (for comparison
    # purposes)
    if os.path.exists(filter_post):
        print('found filter-post-ins.txt, using that for ekf results')
        result['filter'] = []
        ffilter = fileinput.input(filter_post)
        for line in ffilter:
            tokens = re.split('[,\s]+', line.rstrip())
            lat = float(tokens[1])
            lon = float(tokens[2])
            if abs(lat) > 0.0001 and abs(lon) > 0.0001:
                filterpt = Record()
                filterpt.time = float(tokens[0])
                filterpt.lat = lat * d2r
                filterpt.lon = lon * d2r
                filterpt.alt = float(tokens[3])
                filterpt.vn = float(tokens[4])
                filterpt.ve = float(tokens[5])
                filterpt.vd = float(tokens[6])
                filterpt.phi = float(tokens[7]) * d2r
                filterpt.the = float(tokens[8]) * d2r
                psi = float(tokens[9])
                if psi > 180.0:
                    psi = psi - 360.0
                if psi < -180.0:
                    psi = psi + 360.0
                filterpt.psi = psi * d2r
                result['filter'].append(filterpt)

    return result
Esempio n. 7
0
for i in range(0, drl):
    C1 = navpy.angle2dcm(flight_data.psi[i], flight_data.theta[i],
                         flight_data.phi[i]).T
    C2 = navpy.angle2dcm(psi[i], theta[i], phi[i], input_unit='deg').T
    dC = C2.dot(C1.T) - np.eye(3)
    # dC contains delta angle. To match delta quaternion, divide by 2.
    delta_att[i, :] = [-dC[1, 2] / 2.0, dC[0, 2] / 2.0, -dC[0, 1] / 2.0]

lat_ref = estPOS[idx_init[0], 0]
lon_ref = estPOS[idx_init[0], 1]
alt_ref = estPOS[idx_init[0], 2]

ecef_ref = navpy.lla2ecef(lat_ref, lon_ref, alt_ref)

ecef = navpy.lla2ecef(estPOS[:, 0], estPOS[:, 1], estPOS[:, 2])
filter_ned = navpy.ecef2ned(ecef - ecef_ref, lat_ref, lon_ref, alt_ref)

ecef = navpy.lla2ecef(flight_data.lat, flight_data.lon, flight_data.alt)
gnss_ned = navpy.ecef2ned(ecef - ecef_ref, lat_ref, lon_ref, alt_ref)
gnss_ned[0:idx_init[0], :] = np.nan

ecef = navpy.lla2ecef(flight_data.navlat,
                      flight_data.navlon,
                      flight_data.navalt,
                      latlon_unit='rad')
ref_ned = navpy.ecef2ned(ecef - ecef_ref, lat_ref, lon_ref, alt_ref)
ref_ned[0:idx_init[0], :] = np.nan

# ============================= INS PLOTS ======================================
nsig = 3
istart = idx_init[0]
Esempio n. 8
0
    # when processing real data, we have no truth reference
    #C1 = navpy.angle2dcm(flight_data.psi[i],flight_data.theta[i],flight_data.phi[i]).T
    C1 = navpy.angle2dcm(psi[i],theta[i],phi[i],input_unit='deg').T
    C2 = navpy.angle2dcm(psi[i],theta[i],phi[i],input_unit='deg').T
    dC = C2.dot(C1.T)-np.eye(3)
    # dC contains delta angle. To match delta quaternion, divide by 2.
    delta_att[i,:] = [-dC[1,2]/2.0, dC[0,2]/2.0, -dC[0,1]/2.0]

lat_ref = estPOS[idx_init[0],0]
lon_ref = estPOS[idx_init[0],1]
alt_ref = estPOS[idx_init[0],2]

ecef_ref = navpy.lla2ecef(lat_ref,lon_ref,alt_ref)

ecef = navpy.lla2ecef(estPOS[:,0],estPOS[:,1],estPOS[:,2])
filter_ned = navpy.ecef2ned(ecef-ecef_ref,lat_ref,lon_ref,alt_ref)

# when processing real data, we have no truth reference
#ecef = navpy.lla2ecef(flight_data.lat,flight_data.lon,flight_data.alt)
#ecef = navpy.lla2ecef(estPOS[:,0],estPOS[:,1],estPOS[:,2])
#gnss_ned = navpy.ecef2ned(ecef-ecef_ref,lat_ref,lon_ref,alt_ref)
#gnss_ned[0:idx_init[0],:] = np.nan

rawgps = np.nan*np.ones((len(gps_data),3))
for i, gps in enumerate(gps_data):
    rawgps[i,:] = [ gps.lat, gps.lon, gps.alt ]
ecef = navpy.lla2ecef(rawgps[:,0],rawgps[:,1],rawgps[:,2],latlon_unit='deg')
ref_ned = navpy.ecef2ned(ecef-ecef_ref,lat_ref,lon_ref,alt_ref)
ref_ned[0:idx_init[0],:] = np.nan

# ============================= INS PLOTS ======================================
Esempio n. 9
0
def load(flight_dir):
    result = {}
    
    gps_data = []
    filter_data = []

    # load imu/gps data files
    imu_file = os.path.join(flight_dir, "imu.csv")
    gps_file = os.path.join(flight_dir, "gps.csv")
    filter_post = os.path.join(flight_dir, "filter-post-ins.txt")
    
    # calibration by plotting and eye-balling (just finding center point, no
    # normalization cooked into calibration.)
    #hx_coeffs = np.array([ 1.0,  -1.5], dtype=np.float64)
    #hy_coeffs = np.array([ 1.0, -78.5], dtype=np.float64)
    #hz_coeffs = np.array([ 1.0, -156.5], dtype=np.float64)
    
    #~/Projects/PILLS/Phantom\ 3\ Flight\ Data/2016-03-22\ --\ imagery_0012\ -\ 400\ ft\ survey
    #hx_coeffs = np.array([ 0.01857771, -0.18006661], dtype=np.float64)
    #hy_coeffs = np.array([ 0.01856938, -1.20854406], dtype=np.float64)
    #hz_coeffs = np.array([ 0.01559645,  2.81011976], dtype=np.float64)

    # ~/Projects/PILLS/Phantom\ 3\ Flight\ Data/imagery_0009 - 0012
    #hx_coeffs = np.array([ 0.01789447,  3.70605872], dtype=np.float64)
    #hy_coeffs = np.array([ 0.017071,    0.7125617], dtype=np.float64)
    #hz_coeffs = np.array([ 0.01447557, -6.54621951], dtype=np.float64)
    
    # ~/Projects/PILLS/2016-04-04\ --\ imagery_0002
    # ~/Projects/PILLS/2016-04-14\ --\ imagery_0003
    # ~/Projects/PILLS/2016-04-14\ --\ imagery_0004
    #hx_coeffs = np.array([ 0.01658555, -0.07790598], dtype=np.float64)
    #hy_coeffs = np.array([ 0.01880532, -1.26548151], dtype=np.float64)
    #hz_coeffs = np.array([ 0.01339084,  2.61905809], dtype=np.float64)

    # ~/Projects/PILLS/2016-05-12\ --\ imagery_0004
    #hx_coeffs = np.array([ 0.01925678,  0.01527908], dtype=np.float64)
    #hy_coeffs = np.array([ 0.01890112, -1.18040666], dtype=np.float64)
    #hz_coeffs = np.array([ 0.01645011,  2.87769626], dtype=np.float64)

    #hx_func = np.poly1d(hx_coeffs)
    #hy_func = np.poly1d(hy_coeffs)
    #hz_func = np.poly1d(hz_coeffs)

    # ~/Projects/PILLS/2016-06-29\ --\ calibration_0002/
    # mag_affine = np.array(
    #     [[ 0.0223062041, -0.0002700799, -0.0001325525,  1.2016235718],
    #      [-0.0002700799,  0.0229484854,  0.0000356172,  0.1177744077],
    #      [-0.0001325525,  0.0000356172,  0.0206129279, -3.2713740483],
    #      [ 0.          ,  0.          ,  0.          ,  1.          ]]
    # )

    # Phantom 3 - Aug 2016 (ellipse cal)
    # mag_affine = np.array(
    #     [[ 0.0189725067,  0.0000203615,  0.0002139272, -0.0134053645],
    #      [ 0.0000760692,  0.0180178765,  0.0000389461, -1.044762755 ],
    #      [ 0.0002417847,  0.0000458039,  0.0171450614,  2.647911793 ],
    #      [ 0.          ,  0.          ,  0.          ,  1.          ]]
    # )
    # Phantom 3 - Aug 2016 (ekf cal)
    # mag_affine = np.array(
    #     [[ 0.0181297161,  0.000774339,  -0.002037224 , -0.2576406372],
    #      [ 0.0002434548,  0.018469032,   0.0016475328, -0.8452362072],
    #      [ 0.0000145964,  0.000267444,   0.0159433791,  2.5630653789],
    #      [ 0.          ,  0.         ,   0.          ,  1.          ]]
    # )

    # 2017-06-07_23-43-50
    mag_affine = np.array(
        [[ 0.0182094965,  0.0001891445,  0.0005079058, -1.0275778093],
         [ 0.0001891445,  0.0188836673,  0.0003014306, -0.7472003813],
         [ 0.0005079058,  0.0003014306,  0.0176589615,  0.9988130618],
         [ 0.          ,  0.          ,  0.          ,  1.          ]]
    )
    print(mag_affine)

    result['imu'] = []
    with open(imu_file, 'r') as fimu:
        reader = csv.DictReader(fimu)
        for row in reader:
            # print(row)
            imu = Record()
            try:
                imu.time = float(row['Time Stamp (ns since boot)']) / 1000000000.0
                imu.p = float(row['xGyro (rad/s)'])
                imu.q = float(row['yGyro (rad/s)'])
                imu.r = float(row['zGyro (rad/s)'])
                imu.ax = float(row[' xAccel (g)'])*g
                imu.ay = float(row[' yAccel (g)'])*g
                imu.az = float(row[' zAccel (g)'])*g
                imu.hx = float(row[' xMag (uT)']) # not logged
                imu.hy = float(row[' xMag (uT)']) # not logged
                imu.hz = float(row[' xMag (uT)']) # not logged
                temp = row[' Temp (C)']
                if temp != 'N/A':
                    imu.temp = float(row[' Temp (C)']) # not logged
                else:
                    imu.temp = 0.0
                result['imu'].append( imu )
            except:
                print('[IMU] failed to parse incomplete row:', row) 

    result['gps'] = []
    with open(gps_file, 'r') as fgps:
        reader = csv.DictReader(fgps)
        for row in reader:
            #print(row)
            gps = Record()
            try:
                gps.time = float(row['Timestamp (ns since boot)']) / 1000000000.0
                gps.unix_sec = gps.time # hack
                #gps.lat = float(row['Lat (deg)'])
                #gps.lon = float(row['Lon (deg)'])
                #gps.alt = float(row['Alt Geoid EGM 96 (m)'])
                ecefx = float(row['ecefX (cm)'])
                ecefy = float(row['ecefY (cm)'])
                ecefz = float(row['ecefZ (cm)'])
                ecefvx = float(row['ecefVX (cm/s)'])
                ecefvy = float(row['ecefVY (cm/s)'])
                ecefvz = float(row['ecefVZ (cm/s)'])
                gps.sats = int(row['Num SVs Used'])
                # wgs84 position
                pos_source = 'llh'  # 'llh' or 'ecef'
                llh = navpy.ecef2lla([float(ecefx)/100.0,
                                      float(ecefy)/100.0,
                                      float(ecefz)/100.0], "deg")
                gps.lat = llh[0]
                gps.lon = llh[1]
                gps.alt = llh[2]
                # velocity
                ned = navpy.ecef2ned([float(ecefvx)/100.0,
                                      float(ecefvy)/100.0,
                                      float(ecefvz)/100.0],
                                     llh[0], llh[1], llh[2])
                gps.vn = ned[0]
                gps.ve = ned[1]
                gps.vd = ned[2]
                if int(row['Fix Type']) == 3:
                    result['gps'].append(gps)
            except:
                print('[GPS] failed to parse incomplete row:', row) 

    result['filter'] = []
    # load filter (post process) records if they exist (for comparison
    # purposes)
    if os.path.exists(filter_post):
        print('found filter-post-ins.txt, using that for ekf results')
        result['filter'] = []
        ffilter = fileinput.input(filter_post)
        for line in ffilter:
            tokens = re.split('[,\s]+', line.rstrip())
            lat = float(tokens[1])
            lon = float(tokens[2])
            if abs(lat) > 0.0001 and abs(lon) > 0.0001:
                filterpt = Record()
                filterpt.time = float(tokens[0])
                filterpt.lat = lat*d2r
                filterpt.lon = lon*d2r
                filterpt.alt = float(tokens[3])
                filterpt.vn = float(tokens[4])
                filterpt.ve = float(tokens[5])
                filterpt.vd = float(tokens[6])
                filterpt.phi = float(tokens[7])*d2r
                filterpt.the = float(tokens[8])*d2r
                psi = float(tokens[9])
                if psi > 180.0:
                    psi = psi - 360.0
                if psi < -180.0:
                    psi = psi + 360.0
                filterpt.psi = psi*d2r
                result['filter'].append(filterpt)

    return result
Esempio n. 10
0
def load(flight_dir):
    imu_data = []
    gps_data = []
    filter_data = []

    # load imu/gps data files
    imu_file = flight_dir + "/imu.csv"
    gps_file = flight_dir + "/gps.csv"

    # calibration by plotting and eye-balling (just finding center point, no
    # normalization cooked into calibration.)
    #hx_coeffs = np.array([ 1.0,  -1.5], dtype=np.float64)
    #hy_coeffs = np.array([ 1.0, -78.5], dtype=np.float64)
    #hz_coeffs = np.array([ 1.0, -156.5], dtype=np.float64)

    #~/Projects/PILLS/Phantom\ 3\ Flight\ Data/2016-03-22\ --\ imagery_0012\ -\ 400\ ft\ survey
    #hx_coeffs = np.array([ 0.01857771, -0.18006661], dtype=np.float64)
    #hy_coeffs = np.array([ 0.01856938, -1.20854406], dtype=np.float64)
    #hz_coeffs = np.array([ 0.01559645,  2.81011976], dtype=np.float64)

    # ~/Projects/PILLS/Phantom\ 3\ Flight\ Data/imagery_0009 - 0012
    #hx_coeffs = np.array([ 0.01789447,  3.70605872], dtype=np.float64)
    #hy_coeffs = np.array([ 0.017071,    0.7125617], dtype=np.float64)
    #hz_coeffs = np.array([ 0.01447557, -6.54621951], dtype=np.float64)

    # ~/Projects/PILLS/2016-04-04\ --\ imagery_0002
    # ~/Projects/PILLS/2016-04-14\ --\ imagery_0003
    # ~/Projects/PILLS/2016-04-14\ --\ imagery_0004
    #hx_coeffs = np.array([ 0.01658555, -0.07790598], dtype=np.float64)
    #hy_coeffs = np.array([ 0.01880532, -1.26548151], dtype=np.float64)
    #hz_coeffs = np.array([ 0.01339084,  2.61905809], dtype=np.float64)

    # ~/Projects/PILLS/2016-05-12\ --\ imagery_0004
    #hx_coeffs = np.array([ 0.01925678,  0.01527908], dtype=np.float64)
    #hy_coeffs = np.array([ 0.01890112, -1.18040666], dtype=np.float64)
    #hz_coeffs = np.array([ 0.01645011,  2.87769626], dtype=np.float64)

    #hx_func = np.poly1d(hx_coeffs)
    #hy_func = np.poly1d(hy_coeffs)
    #hz_func = np.poly1d(hz_coeffs)

    # ~/Projects/PILLS/2016-06-29\ --\ calibration_0002/
    # mag_affine = np.array(
    #     [[ 0.0223062041, -0.0002700799, -0.0001325525,  1.2016235718],
    #      [-0.0002700799,  0.0229484854,  0.0000356172,  0.1177744077],
    #      [-0.0001325525,  0.0000356172,  0.0206129279, -3.2713740483],
    #      [ 0.          ,  0.          ,  0.          ,  1.          ]]
    # )

    # Phantom 3 - Aug 2016 (ellipse cal)
    mag_affine = np.array(
        [[0.0189725067, 0.0000203615, 0.0002139272, -0.0134053645],
         [0.0000760692, 0.0180178765, 0.0000389461, -1.044762755],
         [0.0002417847, 0.0000458039, 0.0171450614, 2.647911793],
         [0., 0., 0., 1.]])
    # Phantom 3 - Aug 2016 (ekf cal)
    # mag_affine = np.array(
    #     [[ 0.0181297161,  0.000774339,  -0.002037224 , -0.2576406372],
    #      [ 0.0002434548,  0.018469032,   0.0016475328, -0.8452362072],
    #      [ 0.0000145964,  0.000267444,   0.0159433791,  2.5630653789],
    #      [ 0.          ,  0.         ,   0.          ,  1.          ]]
    # )
    print mag_affine

    fimu = fileinput.input(imu_file)
    for line in fimu:
        #print line
        if not re.search('Time', line):
            tokens = line.split(',')
            #print len(tokens)
            if len(tokens) == 11 and isFloat(tokens[10]):
                #print '"' + tokens[10] + '"'
                (time, p, q, r, ax, ay, az, hx, hy, hz, temp) = tokens
                # remap axis before applying mag calibration
                p = -float(p)
                q = float(q)
                r = -float(r)
                ax = -float(ax) * g
                ay = float(ay) * g
                az = -float(az) * g
                hx = -float(hx)
                hy = float(hy)
                hz = -float(hz)
                mag_orientation = 'newer'
                if mag_orientation == 'older':
                    #hx_new = hx_func(float(hx))
                    #hy_new = hy_func(float(hy))
                    #hz_new = hz_func(float(hz))
                    s = [hx, hy, hz]
                elif mag_orientation == 'newer':
                    # remap for 2016-05-12 (0004) data set
                    #hx_new = hx_func(float(-hy))
                    #hy_new = hy_func(float(-hx))
                    #hz_new = hz_func(float(-hz))
                    s = [-hy, -hx, -hz]
                # mag calibration mapping via mag_affine matrix
                hs = np.hstack([s, 1.0])
                hf = np.dot(mag_affine, hs)
                #print hf[:3]
                #norm = np.linalg.norm([hx_new, hy_new, hz_new])
                #hx_new /= norm
                #hy_new /= norm
                #hz_new /= norm

                imu = nav.structs.IMUdata()
                imu.time = float(time) / 1000000.0
                imu.p = p
                imu.q = q
                imu.r = r
                imu.ax = ax
                imu.ay = ay
                imu.az = az
                imu.hx = hf[0]
                imu.hy = hf[1]
                imu.hz = hf[2]
                #float(hf[0]), float(hf[1]), float(hf[2]),
                imu.temp = float(temp)
                imu_data.append(imu)

    fgps = fileinput.input(gps_file)
    for line in fgps:
        if not re.search('Timestamp', line):
            #print line
            tokens = line.split(',')
            #print len(tokens)
            if len(tokens) == 14:
                (time, itow, ecefx, ecefy, ecefz, ecefvx, ecefvy, ecefvz,
                 fixtype, posacc, spdacc, posdop, numsvs, flags) = tokens
            elif len(tokens) == 19:
                (time, itow, lat, lon, alt, ecefx, ecefy, ecefz, ecefvx,
                 ecefvy, ecefvz, fixtype, posacc, spdacc, posdop, numsvs,
                 flags, diff_status, carrier_status) = tokens

            # wgs84 position
            pos_source = 'llh'  # 'llh' or 'ecef'
            llh = navpy.ecef2lla([
                float(ecefx) / 100.0,
                float(ecefy) / 100.0,
                float(ecefz) / 100.0
            ], "deg")
            # velocity
            ned = navpy.ecef2ned([
                float(ecefvx) / 100.0,
                float(ecefvy) / 100.0,
                float(ecefvz) / 100.0
            ], llh[0], llh[1], llh[2])
            if int(numsvs) >= 4:
                gps = nav.structs.GPSdata()
                gps.time = float(time) / 1000000.0
                #gps.status = int(status)
                gps.unix_sec = float(time) / 1000000.0  # make filter happy
                gps.lat = float(lat)
                gps.lon = float(lon)
                gps.alt = float(alt)
                gps.vn = ned[0]
                gps.ve = ned[1]
                gps.vd = ned[2]
                gps_data.append(gps)
    return imu_data, gps_data, filter_data
Esempio n. 11
0
def run_filter(imu_data, gps_data):
    drl = len(imu_data)

    # result structures
    estPOS = np.nan * np.ones((drl, 3))
    estVEL = np.nan * np.ones((drl, 3))
    estATT = np.nan * np.ones((drl, 4))
    estAB = np.nan * np.ones((drl, 4))
    estGB = np.nan * np.ones((drl, 4))

    Pp = np.nan * np.ones((drl, 3))
    Pvel = np.nan * np.ones((drl, 3))
    Patt = np.nan * np.ones((drl, 3))
    Pab = np.nan * np.ones((drl, 3))
    Pgb = np.nan * np.ones((drl, 3))

    stateInnov = np.nan * np.ones((drl, 6))

    plot_time = [0.0] * drl

    # Variable Initializer
    idx_init = []

    # Main Loop
    filter = EKF.Filter()

    gps_index = 1
    nav_init = False
    for i, imu in enumerate(imu_data):
        # walk the gps counter forward as needed
        if imu.time >= gps_data[gps_index].time:
            gps_index += 1
        if gps_index >= len(gps_data):
            # no more gps data, stick on the last record
            gps_index = len(gps_data) - 1
        gps = gps_data[gps_index - 1]
        # print "t(imu) = " + str(imu.time) + " t(gps) = " + str(gps.time)

        # update the filter
        plot_time[i] = imu.time
        est = filter.update(imu, gps, verbose=False)

        # save the results for plotting
        if not nav_init and est.valid:
            nav_init = True
            idx_init.append(i)
        elif not est.valid:
            nav_init = False
        estPOS[i, :] = est.estPOS[:]
        estVEL[i, :] = est.estVEL[:]
        estATT[i, :] = est.estATT[:]
        estAB[i, 0:3] = est.estAB[:]
        estAB[i, 3] = imu.temp
        estGB[i, 0:3] = est.estGB[:]
        estGB[i, 3] = imu.temp
        Pp[i, :] = np.diag(est.P[0:3, 0:3])
        Pvel[i, :] = np.diag(est.P[3:6, 3:6])
        Patt[i, :] = np.diag(est.P[6:9, 6:9])
        Pab[i, :] = np.diag(est.P[9:12, 9:12])
        Pgb[i, :] = np.diag(est.P[12:15, 12:15])
        stateInnov[i, :] = est.stateInnov[:]

    psi, theta, phi = navpy.quat2angle(estATT[:, 0],
                                       estATT[:, 1:4],
                                       output_unit='deg')

    # Calculate Attitude Error
    delta_att = np.nan * np.zeros((drl, 3))
    for i in range(0, drl):
        # when processing real data, we have no truth reference
        #C1 = navpy.angle2dcm(flight_data.psi[i],flight_data.theta[i],flight_data.phi[i]).T
        C1 = navpy.angle2dcm(psi[i], theta[i], phi[i], input_unit='deg').T
        C2 = navpy.angle2dcm(psi[i], theta[i], phi[i], input_unit='deg').T
        dC = C2.dot(C1.T) - np.eye(3)
        # dC contains delta angle. To match delta quaternion, divide by 2.
        delta_att[i, :] = [-dC[1, 2] / 2.0, dC[0, 2] / 2.0, -dC[0, 1] / 2.0]

    lat_ref = estPOS[idx_init[0], 0]
    lon_ref = estPOS[idx_init[0], 1]
    alt_ref = estPOS[idx_init[0], 2]

    ecef_ref = navpy.lla2ecef(lat_ref, lon_ref, alt_ref)

    ecef = navpy.lla2ecef(estPOS[:, 0], estPOS[:, 1], estPOS[:, 2])
    filter_ned = navpy.ecef2ned(ecef - ecef_ref, lat_ref, lon_ref, alt_ref)

    # when processing real data, we have no truth reference
    #ecef = navpy.lla2ecef(flight_data.lat,flight_data.lon,flight_data.alt)
    #ecef = navpy.lla2ecef(estPOS[:,0],estPOS[:,1],estPOS[:,2])
    #gnss_ned = navpy.ecef2ned(ecef-ecef_ref,lat_ref,lon_ref,alt_ref)
    #gnss_ned[0:idx_init[0],:] = np.nan

    rawgps = np.nan * np.ones((len(gps_data), 3))
    for i, gps in enumerate(gps_data):
        rawgps[i, :] = [gps.lat, gps.lon, gps.alt]
    ecef = navpy.lla2ecef(rawgps[:, 0],
                          rawgps[:, 1],
                          rawgps[:, 2],
                          latlon_unit='deg')
    ref_ned = navpy.ecef2ned(ecef - ecef_ref, lat_ref, lon_ref, alt_ref)
    ref_ned[0:idx_init[0], :] = np.nan

    return estPOS, estVEL, estATT, estAB, estGB, Pp, Pvel, Patt, Pab, Pgb, stateInnov, plot_time, idx_init, filter_ned, ref_ned, psi, theta, phi, delta_att
Esempio n. 12
0
def run_filter(imu_data, gps_data):
    drl = len(imu_data)

    # result structures
    estPOS = np.nan * np.ones((drl, 3))
    estVEL = np.nan * np.ones((drl, 3))
    estATT = np.nan * np.ones((drl, 4))
    estAB = np.nan * np.ones((drl, 4))
    estGB = np.nan * np.ones((drl, 4))

    Pp = np.nan * np.ones((drl, 3))
    Pvel = np.nan * np.ones((drl, 3))
    Patt = np.nan * np.ones((drl, 3))
    Pab = np.nan * np.ones((drl, 3))
    Pgb = np.nan * np.ones((drl, 3))

    stateInnov = np.nan * np.ones((drl, 6))

    plot_time = [0.0] * drl

    # Variable Initializer
    idx_init = []

    # Main Loop
    filter = EKF.Filter()

    gps_index = 1
    nav_init = False
    for i, imu in enumerate(imu_data):
        # walk the gps counter forward as needed
        if imu.time >= gps_data[gps_index].time:
            gps_index += 1
        if gps_index >= len(gps_data):
            # no more gps data, stick on the last record
            gps_index = len(gps_data) - 1
        gps = gps_data[gps_index - 1]
        # print "t(imu) = " + str(imu.time) + " t(gps) = " + str(gps.time)

        # update the filter
        plot_time[i] = imu.time
        est = filter.update(imu, gps, verbose=False)

        # save the results for plotting
        if not nav_init and est.valid:
            nav_init = True
            idx_init.append(i)
        elif not est.valid:
            nav_init = False
        estPOS[i, :] = est.estPOS[:]
        estVEL[i, :] = est.estVEL[:]
        estATT[i, :] = est.estATT[:]
        estAB[i, 0:3] = est.estAB[:]
        estAB[i, 3] = imu.temp
        estGB[i, 0:3] = est.estGB[:]
        estGB[i, 3] = imu.temp
        Pp[i, :] = np.diag(est.P[0:3, 0:3])
        Pvel[i, :] = np.diag(est.P[3:6, 3:6])
        Patt[i, :] = np.diag(est.P[6:9, 6:9])
        Pab[i, :] = np.diag(est.P[9:12, 9:12])
        Pgb[i, :] = np.diag(est.P[12:15, 12:15])
        stateInnov[i, :] = est.stateInnov[:]

    psi, theta, phi = navpy.quat2angle(estATT[:, 0], estATT[:, 1:4], output_unit="deg")

    # Calculate Attitude Error
    delta_att = np.nan * np.zeros((drl, 3))
    for i in range(0, drl):
        # when processing real data, we have no truth reference
        # C1 = navpy.angle2dcm(flight_data.psi[i],flight_data.theta[i],flight_data.phi[i]).T
        C1 = navpy.angle2dcm(psi[i], theta[i], phi[i], input_unit="deg").T
        C2 = navpy.angle2dcm(psi[i], theta[i], phi[i], input_unit="deg").T
        dC = C2.dot(C1.T) - np.eye(3)
        # dC contains delta angle. To match delta quaternion, divide by 2.
        delta_att[i, :] = [-dC[1, 2] / 2.0, dC[0, 2] / 2.0, -dC[0, 1] / 2.0]

    lat_ref = estPOS[idx_init[0], 0]
    lon_ref = estPOS[idx_init[0], 1]
    alt_ref = estPOS[idx_init[0], 2]

    ecef_ref = navpy.lla2ecef(lat_ref, lon_ref, alt_ref)

    ecef = navpy.lla2ecef(estPOS[:, 0], estPOS[:, 1], estPOS[:, 2])
    filter_ned = navpy.ecef2ned(ecef - ecef_ref, lat_ref, lon_ref, alt_ref)

    # when processing real data, we have no truth reference
    # ecef = navpy.lla2ecef(flight_data.lat,flight_data.lon,flight_data.alt)
    # ecef = navpy.lla2ecef(estPOS[:,0],estPOS[:,1],estPOS[:,2])
    # gnss_ned = navpy.ecef2ned(ecef-ecef_ref,lat_ref,lon_ref,alt_ref)
    # gnss_ned[0:idx_init[0],:] = np.nan

    rawgps = np.nan * np.ones((len(gps_data), 3))
    for i, gps in enumerate(gps_data):
        rawgps[i, :] = [gps.lat, gps.lon, gps.alt]
    ecef = navpy.lla2ecef(rawgps[:, 0], rawgps[:, 1], rawgps[:, 2], latlon_unit="deg")
    ref_ned = navpy.ecef2ned(ecef - ecef_ref, lat_ref, lon_ref, alt_ref)
    ref_ned[0 : idx_init[0], :] = np.nan

    return (
        estPOS,
        estVEL,
        estATT,
        estAB,
        estGB,
        Pp,
        Pvel,
        Patt,
        Pab,
        Pgb,
        stateInnov,
        plot_time,
        idx_init,
        filter_ned,
        ref_ned,
        psi,
        theta,
        phi,
        delta_att,
    )
Esempio n. 13
0
    def update(self, imu, gps, verbose=True):
        # Check for validity of GNSS at this time
        self.tcpu = imu.time
        self.tow = gps.tow

        # Test 1: navValid flag and the data is indeed new (new Time of Week)
        # Execute Measurement Update if this is true and Test 2 passes
        NEW_GNSS_FLAG = ((gps.valid == 0) &
                         (abs(self.tow - self.last_tow) > 1e-3))

        # Test 2: Check if the delta time of the Time of Week and the
        # CPU time are consistent
        # If this fails, re-initialize the filter. There must have been a glitch
        if NEW_GNSS_FLAG:
            #print self.tcpu, self.last_tcpu, self.tcpu-self.last_tcpu
            #print self.tow, self.last_tow, self.tow-self.last_tow
            if abs((self.tcpu - self.last_tcpu) -
                   (self.tow - self.last_tow)) > 0.5:
                self.TU_COUNT = 0
                self.NAV_INIT = False
                if verbose:
                    print("Time Sync Error -- Request reinitialization")
            # Record the tow and tcpu at this new update
            self.last_tow = self.tow
            self.last_tcpu = self.tcpu

        # Different subroutine executed in the filter
        if not self.NAV_INIT:
            if not self.IMU_CAL_INIT:
                # SUBROUTINE: IMU CALIBRATION,
                # This only happens first time round on the ground. Inflight
                # reinitialization is not the same.
                self.estAB[:] = [0, 0, 0]
                if self.very_first_time:
                    self.very_first_time = False
                    self.estGB[:] = [imu.p, imu.q, imu.r]
                    self.phi = 0
                    self.theta = 0
                else:
                    self.estGB[:] = self.last_estGB[:]*self.TU_COUNT \
                                    + [imu.p, imu.q, imu.r]
                    # Simple AHRS values
                    self.phi = self.phi*self.TU_COUNT \
                               + np.arctan2(-imu.ay, -imu.az)
                    self.theta = self.theta*self.TU_COUNT \
                                 + np.arctan2(imu.ax, np.sqrt(imu.ay**2+imu.az**2))

                self.phi /= (self.TU_COUNT + 1)
                self.theta /= (self.TU_COUNT + 1)
                self.estGB[:] /= (self.TU_COUNT + 1)
                self.estATT[0], self.estATT[1:] = navpy.angle2quat(
                    0, self.theta, self.phi)
                """
                print("t = %7.3f, Gyro Bias Value: [%6.2f, %6.2f, %6.2f] deg/sec" %\
                      (imu.time, np.rad2deg(self.estGB[0]), np.rad2deg(self.estGB[1]), np.rad2deg(self.estGB[2]) ))
                print("t = %7.3f, phi = %6.2f, theta = %6.2f" % (imu.time,np.rad2deg(self.phi),np.rad2deg(self.theta)) )
                """

                self.TU_COUNT += 1
                if self.TU_COUNT >= 35:
                    self.TU_COUNT = 0
                    self.IMU_CAL_INIT = True
                    if verbose:
                        print("t = %7.3f, IMU Calibrated!" % (imu.time))
                    del (self.phi)
                    del (self.theta)
            else:
                if not NEW_GNSS_FLAG:
                    # SUBROUTINE 1: BACKUP NAVIGATION or IN-FLIGHT INITIALIZATION

                    # >>>> AHRS CODE GOES HERE
                    self.estATT[:] = self.last_estATT[:]  # This should be some backup nav mode
                    # <<<<

                    # When still there is no GNSS signal, continue propagating bias
                    self.estAB[:] = self.last_estAB[:]
                    self.estGB[:] = self.last_estGB[:]
                else:
                    # When there is GNSS fix available, initialize all the states
                    # and renew covariance
                    self.estPOS[:] = [gps.lat, gps.lon, gps.alt]
                    self.estVEL[:] = [gps.vn, gps.ve, gps.vd]
                    self.estATT[:] = self.last_estATT[:]

                    #self.estATT[0], self.estATT[1:] = navpy.angle2quat(flight_data.psi[i],flight_data.theta[i],flight_data.phi[i])

                    self.estAB[:] = self.last_estAB[:]
                    self.estGB[:] = self.last_estGB[:]

                    self.init_covariance()

                    #idx_init.append(i)
                    self.NAV_INIT = True
                    if verbose:
                        print("t = %7.3f, Filter (Re-)initialized" %
                              (imu.time))

        elif self.NAV_INIT:
            # SUBROUTINE 2: MAIN FILTER ALGORITHM, INS + GNSS
            # ==== Time-Update ====
            dt = imu.time - self.last_imu.time
            q0, qvec = self.last_estATT[0], self.last_estATT[1:4]

            C_B2N = navpy.quat2dcm(q0, qvec).T

            # 0. Data Acquisition
            f_b=np.array([0.5*(self.last_imu.ax+imu.ax)-self.last_estAB[0],\
                          0.5*(self.last_imu.ay+imu.ay)-self.last_estAB[1],\
                          0.5*(self.last_imu.az+imu.az)-self.last_estAB[2]])

            om_ib=np.array([0.5*(self.last_imu.p+imu.p)-self.last_estGB[0],\
                            0.5*(self.last_imu.q+imu.q)-self.last_estGB[1],\
                            0.5*(self.last_imu.r+imu.r)-self.last_estGB[2]])

            # 1. Attitude Update
            # --> Need to compensate for navrate and earthrate
            dqvec = 0.5 * om_ib * dt
            self.estATT[0], self.estATT[1:4] = navpy.qmult(
                q0, qvec, 1.0, dqvec)

            self.estATT[0] /= np.sqrt(self.estATT[0]**2 \
                                      + la.norm(self.estATT[1:4])**2)
            self.estATT[1:4] /= np.sqrt(self.estATT[0]**2 \
                                        + la.norm(self.estATT[1:4])**2)

            # 2. Velocity Update
            # --> Need to compensate for coriolis effect
            g = np.array([0, 0, 9.81])
            f0, fvec = navpy.qmult(q0, qvec, 0, f_b)
            f_n0, f_nvec = navpy.qmult(f0, fvec, q0, -qvec)
            self.estVEL[:] = self.last_estVEL[:] + (f_nvec + g) * dt

            # 3. Position Update
            dPOS = navpy.llarate(self.last_estVEL[0], self.last_estVEL[1],
                                 self.last_estVEL[2], self.last_estPOS[0],
                                 self.last_estPOS[2])
            dPOS *= dt
            self.estPOS[:] = self.last_estPOS[:] + dPOS

            # 4. Biases are constant
            self.estAB[:] = self.last_estAB[:]
            self.estGB[:] = self.last_estGB[:]

            # 5. Jacobian
            pos2pos = np.zeros((3, 3))
            pos2gs = np.eye(3)
            pos2att = np.zeros((3, 3))
            pos2acc = np.zeros((3, 3))
            pos2gyr = np.zeros((3, 3))

            gs2pos = np.zeros((3, 3))
            gs2pos[2, 2] = -2 * 9.81 / wgs84.R0
            gs2gs = np.zeros((3, 3))
            gs2att = -2 * C_B2N.dot(navpy.skew(f_b))
            gs2acc = -C_B2N
            gs2gyr = np.zeros((3, 3))

            att2pos = np.zeros((3, 3))
            att2gs = np.zeros((3, 3))
            att2att = -navpy.skew(om_ib)
            att2acc = np.zeros((3, 3))
            att2gyr = -0.5 * np.eye(3)

            F = np.zeros((15, 15))
            F[0:3, 0:3] = pos2pos
            F[0:3, 3:6] = pos2gs
            F[0:3, 6:9] = pos2att
            F[0:3, 9:12] = pos2acc
            F[0:3, 12:15] = pos2gyr

            F[3:6, 0:3] = gs2pos
            F[3:6, 3:6] = gs2gs
            F[3:6, 6:9] = gs2att
            F[3:6, 9:12] = gs2acc
            F[3:6, 12:15] = gs2gyr

            F[6:9, 0:3] = att2pos
            F[6:9, 3:6] = att2gs
            F[6:9, 6:9] = att2att
            F[6:9, 9:12] = att2acc
            F[6:9, 12:15] = att2gyr

            F[9:12, 9:12] = -1.0 / self.tau_a * np.eye(3)
            F[12:15, 12:15] = -1.0 / self.tau_g * np.eye(3)

            PHI = np.eye(15) + F * dt

            # 6. Process Noise
            G = np.zeros((15, 12))
            G[3:6, 0:3] = -C_B2N
            G[6:9, 3:6] = att2gyr
            G[9:12, 6:9] = np.eye(3)
            G[12:15, 9:12] = np.eye(3)

            Q = G.dot(self.Rw.dot(G.T)) * dt

            # 7. Covariance Update
            self.P = PHI.dot(self.P.dot(PHI.T)) + Q

            self.TU_COUNT += 1

            if self.TU_COUNT >= 500:
                # Request reinitialization after 12 seconds of no GNSS updates
                self.TU_COUNT = 0
                self.NAV_INIT = False

            if NEW_GNSS_FLAG:
                # ==== Measurement-Update ====
                # 0. Get measurement and make innovations
                ecef_ref = navpy.lla2ecef(self.estPOS[0], self.estPOS[1], 0)
                ins_ecef = navpy.lla2ecef(self.estPOS[0], self.estPOS[1],
                                          self.estPOS[2])
                gnss_ecef = navpy.lla2ecef(gps.lat, gps.lon, gps.alt)

                ins_ned = navpy.ecef2ned(ins_ecef - ecef_ref, self.estPOS[0],
                                         self.estPOS[1], self.estPOS[2])
                gnss_ned = navpy.ecef2ned(gnss_ecef - ecef_ref, self.estPOS[0],
                                          self.estPOS[1], self.estPOS[2])

                dpos = gnss_ned - ins_ned

                gnss_vel = np.array([gps.vn, gps.ve, gps.vd])
                dvel = gnss_vel - self.estVEL[:]

                dy = np.hstack((dpos, dvel))
                self.stateInnov[:] = dy

                # 1. Kalman Gain
                K = self.P.dot(self.H.T)
                K = K.dot(la.inv(self.H.dot(self.P.dot(self.H.T)) + self.R))

                # 2. Covariance Update
                ImKH = np.eye(15) - K.dot(self.H)
                KRKt = K.dot(self.R.dot(K.T))
                self.P = ImKH.dot(self.P.dot(ImKH.T)) + KRKt

                # 3. State Update
                dx = K.dot(dy)

                Rew, Rns = navpy.earthrad(self.estPOS[0])

                self.estPOS[2] -= dx[2]
                self.estPOS[0] += np.rad2deg(dx[0] / (Rew + self.estPOS[2]))
                self.estPOS[1] += np.rad2deg(
                    dx[1] / (Rns + self.estPOS[2]) /
                    np.cos(np.deg2rad(self.estPOS[0])))

                self.estVEL[:] += dx[3:6]

                self.estATT[0], self.estATT[1:4] = navpy.qmult(
                    self.estATT[0], self.estATT[1:4], 1, dx[6:9])

                self.estATT[0] /= np.sqrt(self.estATT[0]**2 \
                                          + la.norm(self.estATT[1:4])**2)
                self.estATT[1:4] /= np.sqrt(self.estATT[0]**2 \
                                            + la.norm(self.estATT[1:4])**2)

                self.estAB[:] += dx[9:12]
                self.estGB[:] += dx[12:15]

                if verbose:
                    print("t = %7.3f, GNSS Update, self.TU_COUNT = %d" %\
                          (gps.time, self.TU_COUNT) )

                self.TU_COUNT = 0

                self.last_estPOS[:] = self.estPOS[:]
                self.last_estVEL[:] = self.estVEL[:]
                self.last_estATT[:] = self.estATT[:]
                self.last_estAB[:] = self.estAB[:]
                self.last_estGB[:] = self.estGB[:]
        else:
            # SUBROUTINE 3: e.g. BACKUP NAVIGATION MODE
            pass

        self.last_imu = imu
        self.last_gps = gps

        result = INSGPS(self.NAV_INIT, imu.time, self.estPOS, self.estVEL,
                        self.estATT, self.estAB, self.estGB, self.P,
                        self.stateInnov)
        return result
Esempio n. 14
0
def load(flight_dir):
    imu_data = []
    gps_data = []
    filter_data = []

    # load imu/gps data files
    imu_file = flight_dir + "/imu.csv"
    gps_file = flight_dir + "/gps.csv"

    # calibration by plotting and eye-balling (just finding center point, no
    # normalization cooked into calibration.)
    #hx_coeffs = np.array([ 1.0,  -1.5], dtype=np.float64)
    #hy_coeffs = np.array([ 1.0, -78.5], dtype=np.float64)
    #hz_coeffs = np.array([ 1.0, -156.5], dtype=np.float64)
    
    #~/Projects/PILLS/Phantom\ 3\ Flight\ Data/2016-03-22\ --\ imagery_0012\ -\ 400\ ft\ survey
    #hx_coeffs = np.array([ 0.01857771, -0.18006661], dtype=np.float64)
    #hy_coeffs = np.array([ 0.01856938, -1.20854406], dtype=np.float64)
    #hz_coeffs = np.array([ 0.01559645,  2.81011976], dtype=np.float64)

    # ~/Projects/PILLS/Phantom\ 3\ Flight\ Data/imagery_0009 - 0012
    #hx_coeffs = np.array([ 0.01789447,  3.70605872], dtype=np.float64)
    #hy_coeffs = np.array([ 0.017071,    0.7125617], dtype=np.float64)
    #hz_coeffs = np.array([ 0.01447557, -6.54621951], dtype=np.float64)
    
    # ~/Projects/PILLS/2016-04-04\ --\ imagery_0002
    # ~/Projects/PILLS/2016-04-14\ --\ imagery_0003
    # ~/Projects/PILLS/2016-04-14\ --\ imagery_0004
    #hx_coeffs = np.array([ 0.01658555, -0.07790598], dtype=np.float64)
    #hy_coeffs = np.array([ 0.01880532, -1.26548151], dtype=np.float64)
    #hz_coeffs = np.array([ 0.01339084,  2.61905809], dtype=np.float64)

    # ~/Projects/PILLS/2016-05-12\ --\ imagery_0004
    #hx_coeffs = np.array([ 0.01925678,  0.01527908], dtype=np.float64)
    #hy_coeffs = np.array([ 0.01890112, -1.18040666], dtype=np.float64)
    #hz_coeffs = np.array([ 0.01645011,  2.87769626], dtype=np.float64)

    #hx_func = np.poly1d(hx_coeffs)
    #hy_func = np.poly1d(hy_coeffs)
    #hz_func = np.poly1d(hz_coeffs)

    # ~/Projects/PILLS/2016-06-29\ --\ calibration_0002/
    # mag_affine = np.array(
    #     [[ 0.0223062041, -0.0002700799, -0.0001325525,  1.2016235718],
    #      [-0.0002700799,  0.0229484854,  0.0000356172,  0.1177744077],
    #      [-0.0001325525,  0.0000356172,  0.0206129279, -3.2713740483],
    #      [ 0.          ,  0.          ,  0.          ,  1.          ]]
    # )

    # Phantom 3 - Aug 2016 (ellipse cal)
    mag_affine = np.array(
        [[ 0.0189725067,  0.0000203615,  0.0002139272, -0.0134053645],
         [ 0.0000760692,  0.0180178765,  0.0000389461, -1.044762755 ],
         [ 0.0002417847,  0.0000458039,  0.0171450614,  2.647911793 ],
         [ 0.          ,  0.          ,  0.          ,  1.          ]]
    )
    # Phantom 3 - Aug 2016 (ekf cal)
    # mag_affine = np.array(
    #     [[ 0.0181297161,  0.000774339,  -0.002037224 , -0.2576406372],
    #      [ 0.0002434548,  0.018469032,   0.0016475328, -0.8452362072],
    #      [ 0.0000145964,  0.000267444,   0.0159433791,  2.5630653789],
    #      [ 0.          ,  0.         ,   0.          ,  1.          ]]
    # )
    print mag_affine
    
    fimu = fileinput.input(imu_file)
    for line in fimu:
        #print line
        if not re.search('Time', line):
            tokens = line.split(',')
            #print len(tokens)
            if len(tokens) == 11 and isFloat(tokens[10]):
                #print '"' + tokens[10] + '"'
                (time, p, q, r, ax, ay, az, hx, hy, hz, temp) = tokens
                # remap axis before applying mag calibration
                p = -float(p)
                q =  float(q)
                r = -float(r)
                ax = -float(ax)*g
                ay =  float(ay)*g
                az = -float(az)*g
                hx = -float(hx)
                hy =  float(hy)
                hz = -float(hz)
                mag_orientation = 'newer'
                if mag_orientation == 'older':
                    #hx_new = hx_func(float(hx))
                    #hy_new = hy_func(float(hy))
                    #hz_new = hz_func(float(hz))
                    s = [hx, hy, hz]
                elif mag_orientation == 'newer':
                    # remap for 2016-05-12 (0004) data set
                    #hx_new = hx_func(float(-hy))
                    #hy_new = hy_func(float(-hx))
                    #hz_new = hz_func(float(-hz))
                    s = [-hy, -hx, -hz]
                # mag calibration mapping via mag_affine matrix
                hs = np.hstack( [s, 1.0] )
                hf = np.dot(mag_affine, hs)
                #print hf[:3]
                #norm = np.linalg.norm([hx_new, hy_new, hz_new])
                #hx_new /= norm
                #hy_new /= norm
                #hz_new /= norm
                
                imu = nav.structs.IMUdata()
                imu.time = float(time)/1000000.0
                imu.p = p
                imu.q = q
                imu.r = r
                imu.ax = ax
                imu.ay = ay
                imu.az = az
                imu.hx = hf[0]
                imu.hy = hf[1]
                imu.hz = hf[2]
                #float(hf[0]), float(hf[1]), float(hf[2]),
                imu.temp = float(temp)
                imu_data.append( imu )

    fgps = fileinput.input(gps_file)
    for line in fgps:
        if not re.search('Timestamp', line):
            #print line
            tokens = line.split(',')
            #print len(tokens)
            if len(tokens) == 14:
                (time, itow, ecefx, ecefy, ecefz, ecefvx, ecefvy, ecefvz,
                 fixtype, posacc, spdacc, posdop, numsvs, flags) = tokens
            elif len(tokens) == 19:
                (time, itow, lat, lon, alt, ecefx, ecefy, ecefz,
                 ecefvx, ecefvy, ecefvz,
                 fixtype, posacc, spdacc, posdop, numsvs, flags,
                 diff_status, carrier_status) = tokens
                
            # wgs84 position
            pos_source = 'llh'  # 'llh' or 'ecef'
            llh = navpy.ecef2lla([float(ecefx)/100.0,
                                  float(ecefy)/100.0,
                                  float(ecefz)/100.0], "deg")
            # velocity
            ned = navpy.ecef2ned([float(ecefvx)/100.0,
                                  float(ecefvy)/100.0,
                                  float(ecefvz)/100.0],
                                 llh[0], llh[1], llh[2])
            if int(numsvs) >= 4:
                gps = nav.structs.GPSdata()
                gps.time = float(time)/1000000.0
                #gps.status = int(status)
                gps.unix_sec = float(time)/1000000.0 # make filter happy
                gps.lat = float(lat)
                gps.lon = float(lon)
                gps.alt = float(alt)
                gps.vn = ned[0]
                gps.ve = ned[1]
                gps.vd = ned[2]
                gps_data.append(gps)
    return imu_data, gps_data, filter_data
Esempio n. 15
0
    def update(self, imu, gps, verbose=True):
        # Check for validity of GNSS at this time
        self.tcpu = imu.time
        self.tow = gps.tow

        # Test 1: navValid flag and the data is indeed new (new Time of Week)
        # Execute Measurement Update if this is true and Test 2 passes
        NEW_GNSS_FLAG = ((gps.valid==0) & (abs(self.tow-self.last_tow) > 1e-3))

        # Test 2: Check if the delta time of the Time of Week and the
        # CPU time are consistent
        # If this fails, re-initialize the filter. There must have been a glitch
        if NEW_GNSS_FLAG:
            #print self.tcpu, self.last_tcpu, self.tcpu-self.last_tcpu
            #print self.tow, self.last_tow, self.tow-self.last_tow
            if abs((self.tcpu-self.last_tcpu) - (self.tow-self.last_tow)) > 0.5:
                self.TU_COUNT = 0
                self.NAV_INIT = False
                if verbose:
                    print("Time Sync Error -- Request reinitialization")
            # Record the tow and tcpu at this new update
            self.last_tow = self.tow
            self.last_tcpu = self.tcpu

        # Different subroutine executed in the filter
        if not self.NAV_INIT:
            if not self.IMU_CAL_INIT:
                # SUBROUTINE: IMU CALIBRATION,
                # This only happens first time round on the ground. Inflight
                # reinitialization is not the same.
                self.estAB[:] = [0,0,0]
                if self.very_first_time:
                    self.very_first_time = False
                    self.estGB[:] = [imu.p, imu.q, imu.r]
                    self.phi = 0
                    self.theta = 0
                else:
                    self.estGB[:] = self.last_estGB[:]*self.TU_COUNT \
                                    + [imu.p, imu.q, imu.r]
                    # Simple AHRS values
                    self.phi = self.phi*self.TU_COUNT \
                               + np.arctan2(-imu.ay, -imu.az)
                    self.theta = self.theta*self.TU_COUNT \
                                 + np.arctan2(imu.ax, np.sqrt(imu.ay**2+imu.az**2))

                self.phi /= (self.TU_COUNT + 1)
                self.theta /= (self.TU_COUNT + 1)
                self.estGB[:] /= (self.TU_COUNT + 1)
                self.estATT[0], self.estATT[1:] = navpy.angle2quat(0, self.theta, self.phi)

                """
                print("t = %7.3f, Gyro Bias Value: [%6.2f, %6.2f, %6.2f] deg/sec" %\
                      (imu.time, np.rad2deg(self.estGB[0]), np.rad2deg(self.estGB[1]), np.rad2deg(self.estGB[2]) ))
                print("t = %7.3f, phi = %6.2f, theta = %6.2f" % (imu.time,np.rad2deg(self.phi),np.rad2deg(self.theta)) )
                """

                self.TU_COUNT += 1
                if self.TU_COUNT >= 35:
                    self.TU_COUNT = 0
                    self.IMU_CAL_INIT = True
                    if verbose:
                        print("t = %7.3f, IMU Calibrated!" % (imu.time))
                    del(self.phi)
                    del(self.theta)
            else:
                if not NEW_GNSS_FLAG:
                    # SUBROUTINE 1: BACKUP NAVIGATION or IN-FLIGHT INITIALIZATION

                    # >>>> AHRS CODE GOES HERE
                    self.estATT[:] = self.last_estATT[:]  # This should be some backup nav mode
                    # <<<<

                    # When still there is no GNSS signal, continue propagating bias
                    self.estAB[:] = self.last_estAB[:]
                    self.estGB[:] = self.last_estGB[:]
                else:
                    # When there is GNSS fix available, initialize all the states
                    # and renew covariance
                    self.estPOS[:] = [gps.lat, gps.lon, gps.alt]
                    self.estVEL[:] = [gps.vn, gps.ve, gps.vd]
                    self.estATT[:] = self.last_estATT[:]

                    #self.estATT[0], self.estATT[1:] = navpy.angle2quat(flight_data.psi[i],flight_data.theta[i],flight_data.phi[i])

                    self.estAB[:] = self.last_estAB[:]
                    self.estGB[:] = self.last_estGB[:]

                    self.init_covariance()

                    #idx_init.append(i)
                    self.NAV_INIT = True
                    if verbose:
                        print("t = %7.3f, Filter (Re-)initialized" % (imu.time) )

        elif self.NAV_INIT:
            # SUBROUTINE 2: MAIN FILTER ALGORITHM, INS + GNSS
            # ==== Time-Update ====
            dt = imu.time - self.last_imu.time
            q0, qvec = self.last_estATT[0], self.last_estATT[1:4]

            C_B2N = navpy.quat2dcm(q0,qvec).T

            # 0. Data Acquisition
            f_b=np.array([0.5*(self.last_imu.ax+imu.ax)-self.last_estAB[0],\
                          0.5*(self.last_imu.ay+imu.ay)-self.last_estAB[1],\
                          0.5*(self.last_imu.az+imu.az)-self.last_estAB[2]])

            om_ib=np.array([0.5*(self.last_imu.p+imu.p)-self.last_estGB[0],\
                            0.5*(self.last_imu.q+imu.q)-self.last_estGB[1],\
                            0.5*(self.last_imu.r+imu.r)-self.last_estGB[2]])

            # 1. Attitude Update
            # --> Need to compensate for navrate and earthrate
            dqvec = 0.5*om_ib*dt
            self.estATT[0], self.estATT[1:4] = navpy.qmult(q0,qvec,1.0,dqvec)

            self.estATT[0] /= np.sqrt(self.estATT[0]**2 \
                                      + la.norm(self.estATT[1:4])**2)
            self.estATT[1:4] /= np.sqrt(self.estATT[0]**2 \
                                        + la.norm(self.estATT[1:4])**2)

            # 2. Velocity Update
            # --> Need to compensate for coriolis effect
            g = np.array([0,0,9.81])
            f0, fvec = navpy.qmult(q0,qvec,0,f_b)
            f_n0,f_nvec = navpy.qmult(f0,fvec,q0,-qvec)
            self.estVEL[:] = self.last_estVEL[:] + (f_nvec+g)*dt

            # 3. Position Update
            dPOS = navpy.llarate(self.last_estVEL[0], self.last_estVEL[1],
                                 self.last_estVEL[2], self.last_estPOS[0],
                                 self.last_estPOS[2])
            dPOS *= dt
            self.estPOS[:] = self.last_estPOS[:] + dPOS

            # 4. Biases are constant
            self.estAB[:] = self.last_estAB[:]
            self.estGB[:] = self.last_estGB[:]

            # 5. Jacobian
            pos2pos = np.zeros((3,3))
            pos2gs = np.eye(3)
            pos2att = np.zeros((3,3))
            pos2acc = np.zeros((3,3))
            pos2gyr = np.zeros((3,3))

            gs2pos = np.zeros((3,3))
            gs2pos[2,2] = -2*9.81/wgs84.R0
            gs2gs = np.zeros((3,3))
            gs2att = -2*C_B2N.dot(navpy.skew(f_b))
            gs2acc = -C_B2N
            gs2gyr = np.zeros((3,3))

            att2pos = np.zeros((3,3))
            att2gs = np.zeros((3,3))
            att2att = -navpy.skew(om_ib)
            att2acc = np.zeros((3,3))
            att2gyr = -0.5*np.eye(3)

            F = np.zeros((15,15))
            F[0:3,0:3] = pos2pos
            F[0:3,3:6] = pos2gs
            F[0:3,6:9] = pos2att
            F[0:3,9:12] = pos2acc
            F[0:3,12:15] = pos2gyr

            F[3:6,0:3] = gs2pos
            F[3:6,3:6] = gs2gs
            F[3:6,6:9] = gs2att
            F[3:6,9:12] = gs2acc
            F[3:6,12:15] = gs2gyr

            F[6:9,0:3] = att2pos
            F[6:9,3:6] = att2gs
            F[6:9,6:9] = att2att
            F[6:9,9:12] = att2acc
            F[6:9,12:15] = att2gyr

            F[9:12,9:12] = -1.0/self.tau_a*np.eye(3)
            F[12:15,12:15] = -1.0/self.tau_g*np.eye(3)

            PHI = np.eye(15) + F*dt

            # 6. Process Noise
            G = np.zeros((15,12))
            G[3:6,0:3] = -C_B2N
            G[6:9,3:6] = att2gyr
            G[9:12,6:9] = np.eye(3)
            G[12:15,9:12] = np.eye(3)

            Q = G.dot(self.Rw.dot(G.T))*dt

            # 7. Covariance Update
            self.P = PHI.dot(self.P.dot(PHI.T)) + Q

            self.TU_COUNT += 1

            if self.TU_COUNT >= 500:
                # Request reinitialization after 12 seconds of no GNSS updates
                self.TU_COUNT = 0
                self.NAV_INIT = False

            if NEW_GNSS_FLAG:
                # ==== Measurement-Update ====
                # 0. Get measurement and make innovations
                ecef_ref = navpy.lla2ecef(self.estPOS[0], self.estPOS[1], 0)
                ins_ecef = navpy.lla2ecef(self.estPOS[0], self.estPOS[1],
                                          self.estPOS[2])
                gnss_ecef = navpy.lla2ecef(gps.lat, gps.lon, gps.alt)

                ins_ned = navpy.ecef2ned(ins_ecef-ecef_ref, self.estPOS[0],
                                         self.estPOS[1], self.estPOS[2])
                gnss_ned = navpy.ecef2ned(gnss_ecef-ecef_ref, self.estPOS[0],
                                          self.estPOS[1], self.estPOS[2])

                dpos = gnss_ned - ins_ned

                gnss_vel = np.array([gps.vn, gps.ve, gps.vd])
                dvel = gnss_vel - self.estVEL[:]

                dy = np.hstack((dpos, dvel))
                self.stateInnov[:] = dy

                # 1. Kalman Gain
                K = self.P.dot(self.H.T)
                K = K.dot( la.inv(self.H.dot(self.P.dot(self.H.T)) + self.R) )

                # 2. Covariance Update
                ImKH = np.eye(15) - K.dot(self.H)
                KRKt = K.dot(self.R.dot(K.T))
                self.P = ImKH.dot(self.P.dot(ImKH.T)) + KRKt

                # 3. State Update
                dx = K.dot(dy)

                Rew, Rns = navpy.earthrad(self.estPOS[0])

                self.estPOS[2] -= dx[2]
                self.estPOS[0] += np.rad2deg(dx[0]/(Rew + self.estPOS[2]))
                self.estPOS[1] += np.rad2deg(dx[1]/(Rns + self.estPOS[2])/np.cos(np.deg2rad(self.estPOS[0])))

                self.estVEL[:] += dx[3:6]

                self.estATT[0], self.estATT[1:4] = navpy.qmult(self.estATT[0], self.estATT[1:4], 1, dx[6:9])

                self.estATT[0] /= np.sqrt(self.estATT[0]**2 \
                                          + la.norm(self.estATT[1:4])**2)
                self.estATT[1:4] /= np.sqrt(self.estATT[0]**2 \
                                            + la.norm(self.estATT[1:4])**2)

                self.estAB[:] += dx[9:12]
                self.estGB[:] += dx[12:15]

                if verbose:
                    print("t = %7.3f, GNSS Update, self.TU_COUNT = %d" %\
                          (gps.time, self.TU_COUNT) )

                self.TU_COUNT = 0

                self.last_estPOS[:] = self.estPOS[:]
                self.last_estVEL[:] = self.estVEL[:]
                self.last_estATT[:] = self.estATT[:]
                self.last_estAB[:] = self.estAB[:]
                self.last_estGB[:] = self.estGB[:]
        else:
            # SUBROUTINE 3: e.g. BACKUP NAVIGATION MODE
            pass

        self.last_imu = imu
        self.last_gps = gps

        result = INSGPS( self.NAV_INIT, imu.time, self.estPOS, self.estVEL,
                         self.estATT, self.estAB, self.estGB,
                         self.P, self.stateInnov )
        return result