예제 #1
0
    def __init__(self, acceleration=-G, magneticField=EARTHMAGFIELD):
        """ calculates the bearing from raw acceleration and magnetometer values
            accelaration in m/s2 and magnetic field in gauss
            angles are saved in radians
            calling w/o arguments creates a vector with phi, theta, psi = 0
        """
        ax, ay, az = toValue(acceleration)
        mx, my, mz = toValue(magneticField)
        if isclose(pythagoras(ax, ay, az), 0., abs_tol=0.001):
            raise ValueError("Acceleration is not significant")
        if isclose(pythagoras(mx, my, mz), 0., abs_tol=0.001):
            raise ValueError("MagneticFlux is not significant")

        phi = -atan2(ay, -az)  #phi = asin(-ay/g*cos(theta))
        theta = asin(ax / g)

        # transformation to horizontal coordinate system - psi = 0
        q = Quaternion(toVector(phi, theta, 0.))
        mHor = q.vecTransformation(magneticField)
        mxh, myh, _ = toValue(mHor)

        psi = atan2(myh, mxh) - DECANGLE

        self.values = toVector(phi, theta, psi)
예제 #2
0
class Velocity_test(unittest.TestCase):
    def test_init(self):
        vel = Velocity(toVector(3, 4, -6))
        self.assertEqual(3, vel.values[0])
        self.assertEqual(4, vel.values[1])
        self.assertEqual(-6, vel.values[2])

    @patch('Velocity.G', toVector(0., 0., 10.))
    def test_update(self):
        vel = Velocity(toVector(3., 1., 2.))
        acc = toVector(0.1, 2., -10.)
        vel.update(acc, Quaternion(toVector(0., 0., 0.)), 1.)
        self.assertEqual(3.1, vel.values[0])
        self.assertEqual(3., vel.values[1])
        self.assertEqual(2., vel.values[2])
예제 #3
0
def plot3DFrame(s, ax):
    """ transforms and plots 3 orthognal vectors representing the orientation
        requires a strapdown-object and an 3D axis as argument
    """
    q = s.quaternion.getConjugatedQuaternion()
    xn = toVector(0, 1, 0)
    yn = toVector(1, 0, 0)
    zn = toVector(0, 0, -1)

    xb = q.vecTransformation(xn)
    yb = q.vecTransformation(yn)
    zb = q.vecTransformation(zn)

    x1, x2, x3 = toValue(xb)
    y1, y2, y3 = toValue(yb)
    z1, z2, z3 = toValue(zb)
    xb = [x1, x2, x3]
    yb = [y1, y2, y3]
    zb = [z1, z2, z3]

    for i in range(3):
        ax.plot([0, xb[i]], [0, yb[i]], zs=[0, zb[i]])

    ax.auto_scale_xyz([-1, 1], [-1, 1], [-1, 1])
    ax.set_xlabel('East')
    ax.set_ylabel('North')
    ax.set_zlabel('Down')

    phi, theta, psi = s.getOrientation()
    vx, vy, vz = s.getVelocity()
    px, py, pz = s.getPosition()
    s1 = ' Roll: %.4f\n Pitch: %.4f\n Yaw: %.4f\n\n' % (
        rad2deg(phi), rad2deg(theta), rad2deg(psi))
    s2 = ' vx: %.2f\n vy: %.2f\n vz: %.2f\n\n' % (vx, vy, vz)
    s3 = ' px: %.2f\n py: %.2f\n pz: %.2f\n' % (px, py, pz)
    plt.figtext(0, 0, s1 + s2 + s3)
예제 #4
0
    def getEulerAngles(self):
        """ calculates Euler angles from the current Quaternion
            result is given in a 3x1 vector in radians
        """

        q0, q1, q2, q3 = toValue(self.values)

        try:
            phi = atan2(2 * (q0 * q1 + q2 * q3), 1 - 2 * (q1**2 + q2**2))
            st = 2 * (q0 * q2 - q3 * q1)
            st = 1 if st > 1 else st  #gimbal lock
            st = -1 if st < -1 else st
            theta = asin(st)
            psi = atan2(2 * (q0 * q3 + q1 * q2), 1 - 2 * (q2**2 + q3**2))
        except ValueError:
            raise ValueError('Quaternion is invalid', q0, q1, q2, q3)

        return toVector(phi, theta, psi)
예제 #5
0
def data_listener():
    s = Strapdown()
    rot_mean = toVector(0., 0., 0.)
    acc_mean = toVector(0., 0., 0.)
    mag_mean = toVector(0., 0., 0.)
    gyroBias = toVector(0., 0., 0.)

    i = 0
    init_time = 1 / 6  #min
    while True:
        if imu.IMURead():
            data = imu.getIMUData()
            gyro = data["gyro"]
            gyro_v = toVector(gyro[0], gyro[1], gyro[2]) - gyroBias
            accel = data["accel"]
            accel_v = toVector(accel[0], accel[1], accel[2]) * -9.80665
            mag = data["compass"]
            mag_v = toVector(mag[0], mag[1], mag[2])
            if not s.isInitialized:
                rot_mean = runningAverage(rot_mean, gyro_v, 1 / i)
                acc_mean = runningAverage(acc_mean, accel_v, 1 / i)
                mag_mean = runningAverage(mag_mean, mag_v, 1 / i)
                if (i * poll_interval / 1000) % 60 == 0:
                    print('Initialized in %.1f minutes\n' %
                          (init_time - i * poll_interval / 1000. / 60., ))
                if i * poll_interval / 1000 >= init_time:
                    s.Initialze(acc_mean, mag_mean)
                    gyroBias = rot_mean

                    print('STRAPDOWN INITIALIZED with %i values\n' % (i, ))
                    print('Initial bearing\n', s.getOrientation())
                    print('Initial velocity\n', s.getVelocity())
                    print('Initial position\n', s.getPosition())
                    print('Initial gyro Bias\n', gyroBias)
            else:
                s.quaternion.update(gyro_v)
                s.velocity.update(accel_v, s.quaternion)
                s.position.update(s.velocity)
                phi, theta, psi = toValue(rad2deg(s.getOrientation()))
                phi_list.append(phi)
                theta_list.append(theta)
                psi_list.append(psi)
                i += 1
                i_list.append(i)
예제 #6
0
from Position import EllipsoidPosition, Position
from GeoLib import ell2xyz
from Velocity import Velocity
from numpy import deg2rad

msg = pynmea2.parse(
    "$GPGGA,132525.000,5233.3292,N,01320.6101,E,2,07,1.38,25.9,M,44.7,M,0000,0000*52"
)
# msg = pynmea2.parse("GPGSA,A,3,14,12,32,29,24,25,31,,,,,,2.67,1.38,2.29*0D")
print('Time: {:} Lat: {:3.4f} Lon: {:3.4f} H: {:3.4f}'.format(
    msg.timestamp, msg.latitude, msg.longitude,
    float(msg.altitude) + float(msg.geo_sep)))

p0 = EllipsoidPosition(
    deg2rad(
        toVector(msg.latitude, msg.longitude,
                 float(msg.altitude) + float(msg.geo_sep))))
p0 = ell2xyz(p0)  #xyz

t0 = msg.timestamp
t0 = (t0.hour * 3600 + t0.minute * 60 + t0.second - 1)

with open(
        'D:\Masterarbeit\Code\Eclipse\ProjectIMU\data\\UltimateGPS\GPRMC_stream.csv',
        'r') as fread:
    streamreader = pynmea2.NMEAStreamReader(fread, 'ignore')
    while 1:
        for msg in streamreader.next():
            if msg.sentence_type == 'GGA':
                he = float(msg.altitude) + float(msg.geo_sep)  #m
                lat = deg2rad(msg.latitude)
                lon = deg2rad(msg.longitude)
예제 #7
0
imu.setSlerpPower(0.02)
imu.setGyroEnable(True)
imu.setAccelEnable(True)
imu.setCompassEnable(True)
print("Recommended Poll Interval: %dmS\n" % imu.IMUGetPollInterval())

SatObs = NMEA_stream.GNSS()
thread = threading.Thread(target=SatObs.stream)
thread.daemon = True
thread.start()
print("Started GPS stream in a new thread")

print("Initializing ...\n")
s = Strapdown()
K = KalmanPVO()
rot_mean = toVector(0.018461137, -0.01460140625, 0.002765854)
accelBias = toVector(0., 0., 0.)
acc_mean = toVector(0., 0., 0.)
mag_mean = toVector(0., 0., 0.)
gyroBias = toVector(0., 0., 0.)
pos_mean = s.getPosition()
dt_mean = 0.01
t_old = 0.

i = 1
j = 1
init_time = 600  # seconds

total_field = 49.5898  # magnitude of magnetic flux

while True:
예제 #8
0
""" contains common variables used during the Strapdown-algorithm
"""

from MathLib import toVector
from numpy import deg2rad

# http://icgem.gfz-potsdam.de/calc
g = 9.80623-0.42

G = toVector(0, 0, g) # m/s2

# https://www.ngdc.noaa.gov/geomag-web/?model=igrf#igrfwmm
#Lat 52.52, Lon 13.40, date 2017-04-13
EARTHMAGFIELD = toVector(18636.7, 1197.4 ,45940.6)/1000 #WMM 
DECANGLE = deg2rad(3. + 40./60. + 34./3600.) # Declination = 3° 40' 34"
예제 #9
0
 def test_init_north(self):
     acc = toVector(0., 0., -10.)
     b = Euler(acc, EARTHMAGFIELD)
     self.assertAlmostEqual(0., b.values[0], delta=0.01)
     self.assertAlmostEqual(0., b.values[1], delta=0.01)
     self.assertAlmostEqual(0., rad2deg((b.values[2])), delta=0.01)
예제 #10
0
def main():
    s = Strapdown()
    K = Kalman()
    rot_mean = toVector(0., 0., 0.)
    acc_mean = toVector(0., 0., 0.)
    mag_mean = toVector(0., 0., 0.)

    # read sensors
    filePath = "data\\adafruit10DOF\\10min_calib_360.csv"
    d = CSVImporter(filePath,
                    columns=range(0, 10),
                    skip_header=7,
                    hasTime=True)
    accelArray, rotationArray, magneticArray = convArray2IMU(d.values)

    # variable sample rate test
    time = d.values[:, 0]
    diff = ([x - time[i - 1] for i, x in enumerate(time)][1:])
    diff.insert(0, 0.0134981505504)

    # realtime 3D plot
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    plt.ion()

    start = datetime.now()
    phi_list = []
    theta_list = []
    psi_list = []
    for i in range(1, int(47999)):  #62247
        dt = diff[i]
        # for 10 - 15 minutes
        if not s.isInitialized:
            rot_mean = runningAverage(rot_mean, rotationArray[:, i], 1 / i)
            acc_mean = runningAverage(acc_mean, accelArray[:, i], 1 / i)
            mag_mean = runningAverage(mag_mean, magneticArray[:, i], 1 / i)
            if i >= 45500:  #100*60*7.5 :
                s.Initialze(acc_mean, mag_mean)
                gyroBias = rot_mean  #toVector(0.019686476,-0.014544547,0.002910090)

                print('STRAPDOWN INITIALIZED with %i values\n' % (i, ))
                print('Initial bearing\n', s.getOrientation() * 180 / pi)
                print('Initial velocity\n', s.getVelocity())
                print('Initial position\n', s.getPosition())
                print('Initial gyro Bias\n', gyroBias * 180 / pi)
        else:
            if i % 10 == 0:  # plot area
                plt.cla()
                fig.texts = []
                plot3DFrame(s, ax)
                plt.draw()
                plt.pause(0.01)

            phi, theta, psi = rad2deg(s.getOrientation())
            phi_list.append(phi)
            theta_list.append(theta)
            psi_list.append(psi)

            acceleration = accelArray[:, i]
            rotationRate = rotationArray[:, i] - gyroBias
            magneticField = magneticArray[:, i]

            s.quaternion.update(rotationRate, dt)
            s.velocity.update(acceleration, s.quaternion, dt)
            s.position.update(s.velocity, dt)

            K.timeUpdate(s.quaternion, dt)
#             if i%10 == 0:
#                 K.measurementUpdate(acceleration, magneticField, s.quaternion)
#
#                 bearingOld = s.getOrientation()
#                 errorQuat = Quaternion(K.bearingError)
#                 s.quaternion *= errorQuat
#                 #s.quaternion.update(K.bearingError/DT) #angle = rate*DT
# #                 print(s.quaternion.values)
#                 bearingNew = s.getOrientation()
# #                 print("Differenz zwischen neuer und alter Lage \n",rad2deg(bearingNew-bearingOld))
#                 gyroBias = gyroBias+K.gyroBias
#                 K.resetState()

    print("Differenz zwischen x Bias End-Start: %E" %
          rad2deg(gyroBias[0] - rot_mean[0]))
    print("Differenz zwischen y Bias End-Start: %E" %
          rad2deg(gyroBias[1] - rot_mean[1]))
    print("Differenz zwischen z Bias End-Start: %E\n" %
          rad2deg(gyroBias[2] - rot_mean[2]))
    print("RMS_dphi = %f deg" % rad2deg(sqrt(K.P[0, 0])))
    print("RMS_dthe = %f deg" % rad2deg(sqrt(K.P[1, 1])))
    print("RMS_dpsi = %f deg" % rad2deg(sqrt(K.P[2, 2])))
    print("RMS_bx = %f deg/s" % rad2deg(sqrt(K.P[3, 3])))
    print("RMS_by = %f deg/s" % rad2deg(sqrt(K.P[4, 4])))
    print("RMS_bz = %f deg/s\n" % rad2deg(sqrt(K.P[5, 5])))
    print('final orientation\n', s.getOrientation() * 180 / pi)
    end = datetime.now()
    diff = end - start
    print('Time needed = ', diff.total_seconds())
    print("RMS_phi = %f deg, max = %f, min = %f\n" %
          (std(phi_list), max(phi_list), min(phi_list)))
    print("RMS_theta = %f deg, max = %f, min = %f\n" %
          (std(theta_list), max(theta_list), min(theta_list)))
    print("RMS_psi = %f deg, max = %f, min = %f\n" %
          (std(psi_list), max(psi_list), min(psi_list)))
    plt.show()
예제 #11
0
def convArray2err(array):
    """ if data includes errors
    """
    err = toVector(array[:, 8], array[:, 9], array[:, 10])
    return err.T
예제 #12
0
from MathLib import toVector, toValue
from math import pi, sin, cos
import matplotlib.pyplot as plt
from matplotlib.pyplot import title, xlabel, ylabel

g = 9.81
phi = 0 * pi / 180
theta = 1 * pi / 180
psi = 0 * pi / 180

# bw = toVector((theta), -(phi), 0)  # 5degree/s
bw = toVector(
    sin(phi) * sin(psi) + cos(phi) * sin(theta) * cos(psi),
    -sin(phi) * cos(psi) + cos(phi) * sin(theta) * sin(psi),
    1 - cos(phi) * cos(theta))

ba = toVector(10, 10, 10)  # mg
ba_ms = ba * g / 1000

for t in range(60):

    dr1 = (1 / 6) * g * (bw) * t**3

    dr2 = (1 / 2) * ba_ms * t**2

    x, y, z = toValue(dr1)

    red_dot, = plt.plot(t, x, "ro")
    blue_dot, = plt.plot(t, y, "bo")
    green_dot, = plt.plot(t, z, "go")
예제 #13
0
 def test_init(self):
     pos = Position(toVector(100, 200, 300))
     self.assertEqual(100, pos.values[0])
     self.assertEqual(200, pos.values[1])
     self.assertEqual(300, pos.values[2])
예제 #14
0
def convArray2PV(array):
    pos = toVector(deg2rad(array[:, 1]), deg2rad(array[:, 2]),
                   array[:, 3])  # rad rad m
    vel = toVector(array[:, 4], array[:, 6], array[:, 6])  # ms
    return pos.T, vel.T
예제 #15
0
 def test_init_Null_mag(self):
     acc = toVector(1., 1., 1.)
     mag = toVector(0., 0., 0.)
     self.assertRaises(ValueError, Euler, acc, mag)
예제 #16
0
 def __init__(self, vector=toVector(0., 0., 0.)):
     """ initialized by a position-vector
         units are given in m 
     """
     self.values = vector
예제 #17
0
 def test_toVector_3D(self):
     vector = toVector(1, 2, 3)
     self.assertEqual(vector[0].item(), 1)
     self.assertEqual(vector[1].item(), 2)
     self.assertEqual(vector[2].item(), 3)
     self.assertEqual(shape(vector), (3, 1))
예제 #18
0
 def test_init_upsidedown(self):
     acc = toVector(0., 0., 9.81)
     mag = toVector(1., 1., 1.)
     b = Euler(acc, mag)
     self.assertEqual(pi, abs(b.values[0]))
     self.assertEqual(0., abs(b.values[1]))
예제 #19
0
 def test_init_plane(self):
     acc = toVector(0., 0., -9.81)
     mag = toVector(1., 1., 1.)
     b = Euler(acc, mag)
     self.assertEqual(0., abs(b.values[0]))
     self.assertEqual(0., abs(b.values[1]))
예제 #20
0
 def test_init(self):
     vel = Velocity(toVector(3, 4, -6))
     self.assertEqual(3, vel.values[0])
     self.assertEqual(4, vel.values[1])
     self.assertEqual(-6, vel.values[2])
예제 #21
0
 def __init__(self, vector=toVector(0., 0., 0.)):
     """ class Velocity propagates the velocity based on acceleration
         initialized by velocity-vector
         units in m/s
     """
     self.values = vector
예제 #22
0
def convArray2IMU(array):  # adafruit 10DOF
    acceleration = toVector(array[:, 4], array[:, 5], array[:, 6]) * -9.80665
    rotationRate = toVector(array[:, 1], array[:, 2], array[:, 3])
    magneticField = toVector(array[:, 7], array[:, 8], array[:, 9])
    return acceleration.T, rotationRate.T, magneticField.T
예제 #23
0
def main():
    vec = toVector(1., 2., 0.)
    plotVector(1, vec)
    plt.show()
예제 #24
0
def convArray2euler(array):
    """ if data includes euler angles
    """
    pose = toVector((array[:, 10]), (array[:, 11]), (array[:, 12]))
    return pose.T
예제 #25
0
 def test_update_2(self):
     p = EllipsoidPosition(toVector(deg2rad(51.),deg2rad(10.),0.))
     vel = Velocity(toVector(10.,20.,0.)) #equal to 1 and 2 meters 
     p.update(vel,0.1)
     self.assertAlmostEqual(51.+8.988903268e-06,rad2deg(p.values[0].item()), delta =10e-06) 
     self.assertAlmostEqual(10.+1.28368253e-05,rad2deg(p.values[1]), delta = 10e-06) 
예제 #26
0
def main():
    """ demo function for measurements saved as CSV file
    """
    s = Strapdown()
    K = KalmanPVO()
    #     kml = simplekml.Kml()

    rot_mean = toVector(0.018461137, -0.01460140625,
                        0.002765854)  # approximate values for gyro bias
    accelBias = toVector(0., 0., 0.)
    acc_mean = toVector(0., 0., 0.)
    mag_mean = toVector(0., 0., 0.)
    pos_mean = s.getPosition()
    dt_mean = 0.01

    # import IMU
    filePath = "data\\adafruit10DOF\\linie_dach_imu.csv"
    dIMU = CSVImporter(filePath,
                       columns=range(0, 13),
                       skip_header=7,
                       hasTime=True)
    accelArray, rotationArray, magneticArray = convArray2IMU(dIMU.values)
    tIMU, deltaArray = convArray2time(dIMU.values)

    # import GPS
    dGPS = CSVImporter("data\\UltimateGPS\\linie_dach_gps.csv",
                       skip_header=1,
                       columns=range(7))
    posArray, velArray = convArray2PV(dGPS.values)
    tGPS, _ = convArray2time(dGPS.values)
    #     PDOP = convArray2err(dGPS.values)

    j = 1  # index for GPS measurements
    for i in range(100, 58164):  # index for IMU measurements
        dt_mean = runningAverage(dt_mean, deltaArray[i], 1)

        # Initialzation
        if not s.isInitialized:
            rot_mean = runningAverage(rot_mean, rotationArray[:, i],
                                      1 / (i + 1))
            acc_mean = runningAverage(acc_mean, accelArray[:, i], 1 / i)
            mag_mean = runningAverage(mag_mean, magneticArray[:, i], 1 / i)
            if tIMU[i] >= tGPS[j]:
                pos_mean = runningAverage(pos_mean, posArray[:, j], 1 / j)
                j += 1
            if i >= 48133:  # for 10 - 15 minutes
                s.Initialze(acc_mean, mag_mean, pos_mean)
                gyroBias = rot_mean

                print(
                    'STRAPDOWN INITIALIZED with %i samples and %i position measurements\n'
                    % (i, j))
                e = Euler()
                e.values = s.getOrientation()
                print('Initial orientation\n', e)
                print('Initial velocity\n', s.velocity)
                print('Initial position\n', s.position)
                e.values = gyroBias
                print('Initial gyro bias\n', e)

        else:
            ###################################### plot area
            if i % 10 == 0:
                plt.figure(1)
                #                 lat, lon, h = s.getPosition()
                #                 plt.plot(i, h, 'ro')
                #                 plt.plot(lon,lat, 'go')
                #                 plotVector(i,s.getVelocity())
                plotVector(i, rad2deg(rad2deg(s.getOrientation())))
#                 kml.newpoint(name=str(i), coords=[(rad2deg(lon), rad2deg(lat), h)])
######################################

            acceleration = accelArray[:, i] - accelBias
            rotationRate = rotationArray[:, i] - gyroBias
            magneticField = magneticArray[:, i]

            s.quaternion.update(rotationRate, dt_mean)
            s.velocity.update(acceleration, s.quaternion, dt_mean)
            s.position.update(s.velocity, dt_mean)

            K.timeUpdate(acceleration, s.quaternion, dt_mean)
            try:
                gpsAvailable = tIMU[i] >= tGPS[j]
            except:  # end of GPS file reached
                gpsAvailable = False

#             if 55450 <= i <= 56450: # simulated GPS outage
#                 gpsAvailable = False
#
            if gpsAvailable or i % 10 == 0:  # doing either complete update or gyro error and bias update
                if gpsAvailable:
                    pos = posArray[:, j]
                    vel = velArray[:, j]
                    j += 1
                else:
                    pos = toVector(0., 0., 0.)
                    vel = toVector(0., 0., 0.)
                K.measurementUpdate(s.quaternion, s.position, s.velocity, pos,
                                    vel, acceleration, magneticField,
                                    gpsAvailable)
                errorQuat = Quaternion(K.oriError)
                s.quaternion = errorQuat * s.quaternion
                s.position.correct(K.posError)
                s.velocity.correct(K.velError)
                gyroBias = gyroBias + K.gyrError
                accelBias = accelBias - K.accError
                K.resetState()

    e.values = s.getOrientation()
    print('\nFinal orientation\n', e)
    print('Final position\n', s.position)

    print("Average sampling rate: {:3.1f}".format(1. / dt_mean))
    #         kml.save("export\\linie_dach.kml")
    plt.show()
예제 #27
0
def convArray2IMU(array):  #arduino 10DOF
    acceleration = toVector(array[:, 4], array[:, 5], array[:, 6]) * -9.80665
    rotationRate = toVector(array[:, 1], array[:, 2], array[:, 3])  #*pi/180
    magneticField = toVector(array[:, 7], array[:, 8], array[:, 9]) * 1
    return acceleration.transpose(), rotationRate.transpose(
    ), magneticField.transpose()
from MathLib import toVector, toValue
from math import pi
g = 9.81

ba = toVector(10, 10, 10)  # mg
ba_ms = ba * g / 1000
bx, by, bz = toValue(ba_ms)

s_phi = -bx/g
print("Lagefehler phi = ", s_phi*180/pi, "deg")
s_theta = bz/g 
print("Lagefehler theta = ", s_theta*180/pi, "deg")
예제 #29
0
def main():
    E = Euler()
    E.values = toVector(pi / 2, pi / 4, pi / 6)
    print('{:rad}'.format(E))
    print(E)