Exemplo n.º 1
0
    def __init__(self, frame="generic"):
        Aircraft.__init__(self)

        self.sim = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sim.connect(('127.0.0.1', 9002))
        self.sim.setblocking(0)
        self.accel_body = Vector3(0, 0, -self.gravity)
        self.frame = frame
        self.last_timestamp = 0
        if self.frame.find("heli") != -1:
            self.decode_servos = self.decode_servos_heli
        else:
            self.decode_servos = self.decode_servos_fixed_wing
Exemplo n.º 2
0
 def transform(self, v3):
     """
     Calculates the vector transformed by this quaternion
     :param v3: Vector3 to be transformed
     :returns: transformed vector
     """
     if isinstance(v3, Vector3):
         t = super(Quaternion, self).transform([v3.x, v3.y, v3.z])
         return Vector3(t[0], t[1], t[2])
     elif len(v3) == 3:
         return super(Quaternion, self).transform(v3)
     else:
         raise TypeError("param v3 is not a vector type")
Exemplo n.º 3
0
    def send_report(self):
        '''send a report to the vehicle control code over MAVLink'''
        from pymavlink import mavutil
        if self.connection is None:
            try:
                self.connection = mavutil.mavlink_connection(self.mavlink_url,
                                                             retries=0)
            except Exception as e:
                return
            print("Gimbal connected to %s" % self.mavlink_url)

        # check for incoming control messages
        while True:
            m = self.connection.recv_match(
                type=['GIMBAL_CONTROL', 'HEARTBEAT'], blocking=False)
            if m is None:
                break
            if m.get_type() == 'GIMBAL_CONTROL':
                self.demanded_angular_rate = Vector3(m.demanded_rate_x,
                                                     m.demanded_rate_y,
                                                     m.demanded_rate_z)

                self.seen_gimbal_control = True
            if m.get_type() == 'HEARTBEAT' and not self.seen_heartbeat:
                self.seen_heartbeat = True
                self.vehicle_component_id = m.get_srcComponent()
                self.connection.mav.srcSystem = m.get_srcSystem()
                self.connection.mav.srcComponent = mavutil.mavlink.MAV_COMP_ID_GIMBAL
                print("Gimbal using srcSystem %u" %
                      self.connection.mav.srcSystem)

        if self.seen_heartbeat:
            now = time.time()
            if now - self.last_heartbeat_t >= 1:
                self.connection.mav.heartbeat_send(
                    mavutil.mavlink.MAV_TYPE_GIMBAL,
                    mavutil.mavlink.MAV_AUTOPILOT_INVALID, 0, 0, 0)
                self.last_heartbeat_t = now

        if self.seen_heartbeat:
            delta_time = now - self.last_report_t
            self.last_report_t = now
            self.connection.mav.gimbal_report_send(
                self.connection.mav.srcSystem,
                mavutil.mavlink.MAV_COMP_ID_GIMBAL, delta_time,
                self.delta_angle.x, self.delta_angle.y, self.delta_angle.z,
                self.delta_velocity.x, self.delta_velocity.y,
                self.delta_velocity.z, self.joint_angles.x,
                self.joint_angles.y, self.joint_angles.z)
            self.delta_velocity.zero()
            self.delta_angle.zero()
Exemplo n.º 4
0
def magfit(logfile):
    '''find best magnetometer offset fit to a log file'''

    print("Processing log %s" % filename)

    # open the log file
    mlog = mavutil.mavlink_connection(filename, notimestamps=opts.notimestamps)

    data = []
    mag = None
    offsets = Vector3(0, 0, 0)

    # now gather all the data
    while True:
        # get the next MAVLink message in the log
        m = mlog.recv_match(condition=opts.condition)
        if m is None:
            break
        if m.get_type() == "SENSOR_OFFSETS":
            # update offsets that were used during this flight
            offsets = Vector3(m.mag_ofs_x, m.mag_ofs_y, m.mag_ofs_z)
        if m.get_type() == "RAW_IMU" and offsets != None:
            # extract one mag vector, removing the offsets that were
            # used during that flight to get the raw sensor values
            mag = Vector3(m.xmag, m.ymag, m.zmag) - offsets
            data.append(mag)

    print("Extracted %u data points" % len(data))
    print("Current offsets: %s" % offsets)

    # run the fitting algorithm
    ofs = offsets
    ofs = Vector3(0, 0, 0)
    for r in range(opts.repeat):
        ofs = find_offsets(data, ofs)
        print('Loop %u offsets %s' % (r, ofs))
        sys.stdout.flush()
    print("New offsets: %s" % ofs)
    def __init__(self):
        self.home_latitude = 0
        self.home_longitude = 0
        self.home_altitude = 0
        self.ground_level = 0
        self.frame_height = 0.0

        self.latitude = self.home_latitude
        self.longitude = self.home_longitude
        self.altitude = self.home_altitude

        self.dcm = Matrix3()

        # rotation rate in body frame
        self.gyro = Vector3(0, 0, 0)  # rad/s

        self.velocity = Vector3(0, 0, 0)  # m/s, North, East, Down
        self.position = Vector3(0, 0, 0)  # m North, East, Down
        self.mass = 0.0
        self.update_frequency = 50  # in Hz
        self.gravity = 9.8  # m/s/s
        self.accelerometer = Vector3(0, 0, -self.gravity)

        self.wind = util.Wind('0,0,0')
Exemplo n.º 6
0
def EarthRatesToBodyRates(dcm, earth_rates):
    '''convert the angular velocities from earth frame to
    body frame. Thanks to James Goppert for the formula

    all inputs and outputs are in radians

    returns a gyro vector in body frame, in rad/s
    '''
    from math import sin, cos

    (phi, theta, psi) = dcm.to_euler()
    phiDot = earth_rates.x
    thetaDot = earth_rates.y
    psiDot = earth_rates.z

    p = phiDot - psiDot * sin(theta)
    q = cos(phi) * thetaDot + sin(phi) * psiDot * cos(theta)
    r = cos(phi) * psiDot * cos(theta) - sin(phi) * thetaDot
    return Vector3(p, q, r)
    def update_position(self, delta_time):
        '''update lat/lon/alt from position'''

        radius_of_earth = 6378100.0  # in meters
        dlat = math.degrees(math.atan(self.position.x / radius_of_earth))
        self.latitude = self.home_latitude + dlat
        lon_scale = math.cos(math.radians(self.latitude))
        dlon = math.degrees(math.atan(
            self.position.y / radius_of_earth)) / lon_scale
        self.longitude = self.home_longitude + dlon

        self.altitude = self.home_altitude - self.position.z

        velocity_body = self.dcm.transposed() * self.velocity

        # force the acceleration to mostly be from gravity. We should be using 100% accel_body,
        # but right now that flies very badly as the AHRS system can't do centripetal correction
        # for multicopters. This is a compromise until we get that sorted out
        accel_true = self.accel_body
        accel_fake = self.dcm.transposed() * Vector3(0, 0, -self.gravity)
        self.accelerometer = (accel_true * 0.5) + (accel_fake * 0.5)
Exemplo n.º 8
0
    def accel(self, velocity, deltat=None):
        '''return current wind acceleration in ground frame.  The
           velocity is a Vector3 of the current velocity of the aircraft
           in earth frame, m/s'''
        from math import radians

        (speed, direction) = self.current(deltat=deltat)

        # wind vector
        v = Vector3(speed, 0, 0)
        m = Matrix3()
        m.from_euler(0, 0, radians(direction))
        wind = m.transposed() * v

        # relative wind vector
        relwind = wind - velocity

        # add in cross-section effect
        a = relwind * self.cross_section

        return a
Exemplo n.º 9
0
def BodyRatesToEarthRates(dcm, gyro):
    '''convert the angular velocities from body frame to
    earth frame.

    all inputs and outputs are in radians/s

    returns a earth rate vector
    '''
    from math import sin, cos, tan, fabs

    p = gyro.x
    q = gyro.y
    r = gyro.z

    (phi, theta, psi) = dcm.to_euler()

    phiDot = p + tan(theta) * (q * sin(phi) + r * cos(phi))
    thetaDot = q * cos(phi) - r * sin(phi)
    if fabs(cos(theta)) < 1.0e-20:
        theta += 1.0e-10
    psiDot = (q * sin(phi) + r * cos(phi)) / cos(theta)
    return Vector3(phiDot, thetaDot, psiDot)
Exemplo n.º 10
0
def magfit(logfile):
    '''find best magnetometer offset fit to a log file'''

    print("Processing log %s" % filename)

    # open the log file
    flog = open(filename, mode='r')

    data = []
    data_no_motors = []
    mag = None
    offsets = None
    
    # now gather all the data
    for line in flog:
        if not line.startswith('COMPASS,'):
            continue
        line = line.rstrip()
        line = line.replace(' ', '')
        a = line.split(',')
        ofs = Vector3(float(a[4]), float(a[5]), float(a[6]))
        if offsets is None:
            initial_offsets = ofs
        offsets = ofs
        motor_ofs = Vector3(float(a[7]), float(a[8]), float(a[9]))
        mag = Vector3(float(a[1]), float(a[2]), float(a[3]))
        mag = mag - offsets
        data.append(mag)
        data_no_motors.append(mag - motor_ofs)

    print("Extracted %u data points" % len(data))
    print("Current offsets: %s" % initial_offsets)

    # run the fitting algorithm
    ofs = initial_offsets
    for r in range(opts.repeat):
        ofs = find_offsets(data, ofs)
        plot_corrected_field('plot.dat', data, ofs)
        plot_corrected_field('initial.dat', data, initial_offsets)
        plot_corrected_field('zero.dat', data, Vector3(0,0,0))
        plot_corrected_field('hand.dat', data, Vector3(-25,-8,-2))
        plot_corrected_field('zero-no-motors.dat', data_no_motors, Vector3(0,0,0))
        print('Loop %u offsets %s' % (r, ofs))
        sys.stdout.flush()
    print("New offsets: %s" % ofs)
Exemplo n.º 11
0
    def drag(self, velocity, deltat=None, testing=None):
        '''return current wind force in Earth frame.  The velocity parameter is
           a Vector3 of the current velocity of the aircraft in earth frame, m/s'''
        from math import radians

        # (m/s, degrees) : wind vector as a magnitude and angle.
        (speed, direction) = self.current(deltat=deltat)
        # speed = self.speed
        # direction = self.direction

        # Get the wind vector.
        w = toVec(speed, radians(direction))

        obj_speed = velocity.length()

        # Compute the angle between the object vector and wind vector by taking
        # the dot product and dividing by the magnitudes.
        d = w.length() * obj_speed
        if d == 0: 
            alpha = 0
        else: 
            alpha = acos((w * velocity) / d)

        # Get the relative wind speed and angle from the object.  Note that the
        # relative wind speed includes the velocity of the object; i.e., there
        # is a headwind equivalent to the object's speed even if there is no
        # absolute wind.
        (rel_speed, beta) = apparent_wind(speed, obj_speed, alpha)

        # Return the vector of the relative wind, relative to the coordinate
        # system.
        relWindVec = toVec(rel_speed, beta + atan2(velocity.y, velocity.x))

        # Combine them to get the acceleration vector.
        return Vector3( acc(relWindVec.x, drag_force(self, relWindVec.x))
                      , acc(relWindVec.y, drag_force(self, relWindVec.y))
                      , 0 )
Exemplo n.º 12
0
def gps_velocity_old(GPS_RAW_INT):
    '''return GPS velocity vector'''
    return Vector3(
        GPS_RAW_INT.vel * 0.01 * cos(radians(GPS_RAW_INT.cog * 0.01)),
        GPS_RAW_INT.vel * 0.01 * sin(radians(GPS_RAW_INT.cog * 0.01)), 0)
Exemplo n.º 13
0
def earth_accel(RAW_IMU, ATTITUDE):
    '''return earth frame acceleration vector'''
    r = rotation(ATTITUDE)
    accel = Vector3(RAW_IMU.xacc, RAW_IMU.yacc, RAW_IMU.zacc) * 9.81 * 0.001
    return r * accel
Exemplo n.º 14
0
    def update(self):
        '''update the gimbal state'''

        # calculate delta time in seconds
        now = time.time()
        delta_t = now - self.last_update_t
        self.last_update_t = now

        if self.dcm is None:
            # start with copter rotation matrix
            self.dcm = self.vehicle.dcm.copy()

        # take a copy of the demanded rates to bypass the limiter function for testing
        demRateRaw = self.demanded_angular_rate

        # 1)  Rotate the copters rotation rates into the gimbals frame of reference
        # copterAngRate_G = transpose(DCMgimbal)*DCMcopter*copterAngRate
        copterAngRate_G = self.dcm.transposed(
        ) * self.vehicle.dcm * self.vehicle.gyro
        #print("copterAngRate_G ", copterAngRate_G)

        # 2) Subtract the copters body rates to obtain a copter relative rotational
        # rate vector (X,Y,Z) in gimbal sensor frame
        # relativeGimbalRate(X,Y,Z) = gimbalRateDemand - copterAngRate_G
        relativeGimbalRate = self.demanded_angular_rate - copterAngRate_G
        #print("relativeGimbalRate ", relativeGimbalRate)

        # calculate joint angles (euler312 order)
        # calculate copter -> gimbal rotation matrix
        rotmat_copter_gimbal = self.dcm.transposed() * self.vehicle.dcm
        self.joint_angles = Vector3(
            *rotmat_copter_gimbal.transposed().to_euler312())
        #print("joint_angles ", self.joint_angles)

        # 4)  For each of the three joints, calculate upper and lower rate limits
        # from the corresponding angle limits and current joint angles
        #
        # upperRatelimit = (jointAngle - lowerAngleLimit) * travelLimitGain
        # lowerRatelimit = (jointAngle - upperAngleLimit) * travelLimitGain
        #
        # travelLimitGain is equal to the inverse of the bump stop time constant and
        # should be set to something like 20 initially. If set too high it can cause
        # the rates to 'ring' when they the limiter is in force, particularly given
        # we are using a first order numerical integration.
        upperRatelimit = -(self.joint_angles -
                           self.upper_joint_limits) * self.travelLimitGain
        lowerRatelimit = -(self.joint_angles -
                           self.lower_joint_limits) * self.travelLimitGain

        # 5) Calculate the gimbal joint rates (roll, elevation, azimuth)
        #
        # gimbalJointRates(roll, elev, azimuth) = Matrix*relativeGimbalRate(X,Y,Z)
        #
        # where matrix =
        #
        # +-                                                                  -+
        # |          cos(elevAngle),        0,         sin(elevAngle)          |
        # |                                                                    |
        # |  sin(elevAngle) tan(rollAngle), 1, -cos(elevAngle) tan(rollAngle)  |
        # |                                                                    |
        # |           sin(elevAngle)                   cos(elevAngle)          |
        # |         - --------------,       0,         --------------          |
        # |           cos(rollAngle)                   cos(rollAngle)          |
        # +-                                                                  -+
        rollAngle = self.joint_angles.x
        elevAngle = self.joint_angles.y
        matrix = Matrix3(
            Vector3(cos(elevAngle), 0, sin(elevAngle)),
            Vector3(
                sin(elevAngle) * tan(rollAngle), 1,
                -cos(elevAngle) * tan(rollAngle)),
            Vector3(-sin(elevAngle) / cos(rollAngle), 0,
                    cos(elevAngle) / cos(rollAngle)))
        gimbalJointRates = matrix * relativeGimbalRate
        #print("lowerRatelimit ", lowerRatelimit)
        #print("upperRatelimit ", upperRatelimit)
        #print("gimbalJointRates ", gimbalJointRates)

        # 6) Apply the rate limits from 4)
        gimbalJointRates.x = constrain(gimbalJointRates.x, lowerRatelimit.x,
                                       upperRatelimit.x)
        gimbalJointRates.y = constrain(gimbalJointRates.y, lowerRatelimit.y,
                                       upperRatelimit.y)
        gimbalJointRates.z = constrain(gimbalJointRates.z, lowerRatelimit.z,
                                       upperRatelimit.z)

        # 7) Convert the modified gimbal joint rates to body rates (still copter
        # relative)
        # relativeGimbalRate(X,Y,Z) = Matrix * gimbalJointRates(roll, elev, azimuth)
        #
        # where Matrix =
        #
        #   +-                                                   -+
        #   |  cos(elevAngle), 0, -cos(rollAngle) sin(elevAngle)  |
        #   |                                                     |
        #   |         0,       1,         sin(rollAngle)          |
        #   |                                                     |
        #   |  sin(elevAngle), 0,  cos(elevAngle) cos(rollAngle)  |
        #   +-                                                   -+
        matrix = Matrix3(
            Vector3(cos(elevAngle), 0, -cos(rollAngle) * sin(elevAngle)),
            Vector3(0, 1, sin(rollAngle)),
            Vector3(sin(elevAngle), 0,
                    cos(elevAngle) * cos(rollAngle)))
        relativeGimbalRate = matrix * gimbalJointRates

        # 8) Add to the result from step 1) to obtain the demanded gimbal body rates
        # in an inertial frame of reference
        # demandedGimbalRatesInertial(X,Y,Z)  = relativeGimbalRate(X,Y,Z) + copterAngRate_G
        demandedGimbalRatesInertial = relativeGimbalRate + copterAngRate_G
        #if now - self.last_print_t >= 1.0:
        #    print("demandedGimbalRatesInertial ", demandedGimbalRatesInertial)

        # for the moment we will set gyros equal to demanded_angular_rate
        self.gimbal_angular_rate = demRateRaw  #demandedGimbalRatesInertial + self.true_gyro_bias - self.supplied_gyro_bias

        # update rotation of the gimbal
        self.dcm.rotate(self.gimbal_angular_rate * delta_t)
        self.dcm.normalize()

        # calculate copter -> gimbal rotation matrix
        rotmat_copter_gimbal = self.dcm.transposed() * self.vehicle.dcm

        # calculate joint angles (euler312 order)
        self.joint_angles = Vector3(
            *rotmat_copter_gimbal.transposed().to_euler312())

        # update observed gyro
        self.gyro = self.gimbal_angular_rate + self.true_gyro_bias

        # update delta_angle (integrate)
        self.delta_angle += self.gyro * delta_t

        # calculate accel in gimbal body frame
        copter_accel_earth = self.vehicle.dcm * self.vehicle.accel_body
        accel = self.dcm.transposed() * copter_accel_earth

        # integrate velocity
        self.delta_velocity += accel * delta_t

        # see if we should do a report
        if now - self.last_report_t >= 1.0 / self.reporting_rate:
            self.send_report()
            self.last_report_t = now

        if now - self.last_print_t >= 1.0:
            self.last_print_t = now
            # calculate joint angles (euler312 order)
            Euler312 = Vector3(*self.dcm.to_euler312())
            print("Euler Angles 312 %6.1f %6.1f %6.1f" % (degrees(
                Euler312.z), degrees(Euler312.x), degrees(Euler312.y)))
Exemplo n.º 15
0
def gps_velocity(GLOBAL_POSITION_INT):
    '''return GPS velocity vector'''
    return Vector3(GLOBAL_POSITION_INT.vx, GLOBAL_POSITION_INT.vy,
                   GLOBAL_POSITION_INT.vz) * 0.01
Exemplo n.º 16
0
    def update(self, servos):
        for i in range(0, len(self.motors)):
            servo = servos[self.motors[i].servo - 1]
            if servo <= 0.0:

                self.motor_speed[i] = 0
            else:
                self.motor_speed[i] = servo

        m = self.motor_speed

        # how much time has passed?
        t = self.time_now
        delta_time = t - self.last_time
        self.last_time = t

        # rotational acceleration, in rad/s/s, in body frame
        rot_accel = Vector3(0, 0, 0)
        thrust = 0.0
        for i in range(len(self.motors)):
            rot_accel.x += -radians(5000.0) * math.sin(
                radians(self.motors[i].angle)) * m[i]
            rot_accel.y += radians(5000.0) * math.cos(
                radians(self.motors[i].angle)) * m[i]
            if self.motors[i].clockwise:
                rot_accel.z -= m[i] * radians(400.0)
            else:
                rot_accel.z += m[i] * radians(400.0)
            thrust += m[i] * self.thrust_scale  # newtons

        # rotational air resistance
        rot_accel.x -= self.gyro.x * radians(
            5000.0) / self.terminal_rotation_rate
        rot_accel.y -= self.gyro.y * radians(
            5000.0) / self.terminal_rotation_rate
        rot_accel.z -= self.gyro.z * radians(
            400.0) / self.terminal_rotation_rate

        # update rotational rates in body frame
        self.gyro += rot_accel * delta_time

        # update attitude
        self.dcm.rotate(self.gyro * delta_time)
        self.dcm.normalize()

        # air resistance
        air_resistance = -self.velocity * (self.gravity /
                                           self.terminal_velocity)

        accel_body = Vector3(0, 0, -thrust / self.mass)
        accel_earth = self.dcm * accel_body
        accel_earth += Vector3(0, 0, self.gravity)
        accel_earth += air_resistance

        # add in some wind (turn force into accel by dividing by mass).
        # NOTE: disable this drag correction until we work out
        # why it is blowing up
        # accel_earth += self.wind.drag(self.velocity) / self.mass

        # if we're on the ground, then our vertical acceleration is limited
        # to zero. This effectively adds the force of the ground on the aircraft
        if self.on_ground() and accel_earth.z > 0:
            accel_earth.z = 0

        # work out acceleration as seen by the accelerometers. It sees the kinematic
        # acceleration (ie. real movement), plus gravity
        self.accel_body = self.dcm.transposed() * (
            accel_earth + Vector3(0, 0, -self.gravity))

        # new velocity vector
        self.velocity += accel_earth * delta_time

        # new position vector
        old_position = self.position.copy()
        self.position += self.velocity * delta_time

        # constrain height to the ground
        if self.on_ground():
            if not self.on_ground(old_position):
                print("Hit ground at %f m/s" % (self.velocity.z))

            self.velocity = Vector3(0, 0, 0)
            # zero roll/pitch, but keep yaw
            (r, p, y) = self.dcm.to_euler()
            self.dcm.from_euler(0, 0, y)

            self.position = Vector3(
                self.position.x, self.position.y,
                -(self.ground_level + self.frame_height - self.home_altitude))

        # update lat/lon/altitude
        self.update_position(delta_time)
Exemplo n.º 17
0
    def __init__(self, vehicle):
        # vehicle is the vehicle (usually a multicopter) that the gimbal is attached to
        self.vehicle = vehicle

        # URL of SITL 2nd telem port
        self.mavlink_url = 'tcp:127.0.0.1:5762'

        # rotation matrix (gimbal body -> earth)
        self.dcm = None

        # time of last update
        self.last_update_t = time.time()

        # true angular rate of gimbal in body frame (rad/s)
        self.gimbal_angular_rate = Vector3()

        # observed angular rate (including biases)
        self.gyro = Vector3()

        # joint angles, in radians. in yaw/roll/pitch order. Relative to fwd.
        # So 0,0,0 points forward.
        # Pi/2,0,0 means pointing right
        # 0, Pi/2, 0 means pointing fwd, but rolled 90 degrees to right
        # 0, 0, -Pi/2, means pointing down
        self.joint_angles = Vector3()

        # physical constraints on joint angles in (roll, pitch, azimuth) order
        self.lower_joint_limits = Vector3(radians(-40), radians(-135),
                                          radians(-7.5))
        self.upper_joint_limits = Vector3(radians(40), radians(45),
                                          radians(7.5))
        self.travelLimitGain = 20

        # true gyro bias
        self.true_gyro_bias = Vector3()

        ##################################
        # reporting variables. gimbal pushes these to vehicle code over MAVLink at approx 100Hz

        # reporting rate in Hz
        self.reporting_rate = 100

        # integral of gyro vector over last time interval. In radians
        self.delta_angle = Vector3()

        # integral of accel vector over last time interval. In m/s
        self.delta_velocity = Vector3()
        # we also push joint_angles

        ##################################
        # control variables from the vehicle

        # angular rate in rad/s. In body frame of gimbal
        self.demanded_angular_rate = Vector3(radians(0), radians(0),
                                             radians(0))

        # gyro bias provided by EKF on vehicle. In rad/s.
        # Should be subtracted from the gyro readings to get true body rotatation rates
        self.supplied_gyro_bias = Vector3()

        ###################################
        # communication variables
        self.connection = None
        self.last_report_t = time.time()
        self.last_heartbeat_t = time.time()
        self.seen_heartbeat = False
        self.seen_gimbal_control = False
        self.last_print_t = time.time()
        self.vehicle_component_id = None
        self.last_report_t = time.time()
Exemplo n.º 18
0
#!/usr/bin/env python
# simple test of wind generation code

import util, time, random
from rotmat import Vector3

wind = util.Wind('7,90,0.1')

t0 = time.time()
velocity = Vector3(0, 0, 0)

t = 0
deltat = 0.01

while t < 60:
    print("%.4f %f" % (t, wind.drag(velocity, deltat=deltat).length()))
    t += deltat
Exemplo n.º 19
0
def toVec(magnitude, angle):
    v = Vector3(magnitude, 0, 0)
    m = Matrix3()
    m.from_euler(0, 0, angle)
    return m.transposed() * v
Exemplo n.º 20
0
def gps_velocity_df(GPS):
    '''return GPS velocity vector'''
    vx = GPS.Spd * cos(radians(GPS.GCrs))
    vy = GPS.Spd * sin(radians(GPS.GCrs))
    return Vector3(vx, vy, GPS.VZ)
Exemplo n.º 21
0
def earth_accel_df(IMU, ATT):
    '''return earth frame acceleration vector from df log'''
    r = rotation_df(ATT)
    accel = Vector3(IMU.AccX, IMU.AccY, IMU.AccZ)
    return r * accel
Exemplo n.º 22
0
def magfit(logfile):
    '''find best magnetometer offset fit to a log file'''

    print("Processing log %s" % filename)
    mlog = mavutil.mavlink_connection(filename, notimestamps=opts.notimestamps)

    data = []

    last_t = 0
    offsets = Vector3(0, 0, 0)
    motor_ofs = Vector3(0, 0, 0)
    motor = 0.0

    # now gather all the data
    while True:
        m = mlog.recv_match(condition=opts.condition)
        if m is None:
            break
        if m.get_type() == "PARAM_VALUE" and m.param_id == "RC3_MIN":
            rc3_min = float(m.param_value)
        if m.get_type() == "SENSOR_OFFSETS":
            # update current offsets
            offsets = Vector3(m.mag_ofs_x, m.mag_ofs_y, m.mag_ofs_z)
        if m.get_type() == "SERVO_OUTPUT_RAW":
            motor_pwm = m.servo1_raw + m.servo2_raw + m.servo3_raw + m.servo4_raw
            motor_pwm *= 0.25
            rc3_min = mlog.param('RC3_MIN', 1100)
            rc3_max = mlog.param('RC3_MAX', 1900)
            motor = (motor_pwm - rc3_min) / (rc3_max - rc3_min)
            if motor > 1.0:
                motor = 1.0
            if motor < 0.0:
                motor = 0.0
        if m.get_type() == "RAW_IMU":
            mag = Vector3(m.xmag, m.ymag, m.zmag)
            # add data point after subtracting the current offsets
            data.append((mag - offsets + noise(), motor))

    print("Extracted %u data points" % len(data))
    print("Current offsets: %s" % offsets)

    data = select_data(data)

    # do an initial fit with all data
    (offsets, motor_ofs, field_strength) = fit_data(data)

    for count in range(3):
        # sort the data by the radius
        data.sort(lambda a, b: radius_cmp(a, b, offsets, motor_ofs))

        print("Fit %u    : %s  %s field_strength=%6.1f to %6.1f" %
              (count, offsets, motor_ofs, radius(data[0], offsets, motor_ofs),
               radius(data[-1], offsets, motor_ofs)))

        # discard outliers, keep the middle 3/4
        data = data[len(data) / 8:-len(data) / 8]

        # fit again
        (offsets, motor_ofs, field_strength) = fit_data(data)

    print("Final    : %s  %s field_strength=%6.1f to %6.1f" %
          (offsets, motor_ofs, radius(data[0], offsets, motor_ofs),
           radius(data[-1], offsets, motor_ofs)))
    print "mavgraph.py '%s' 'mag_field(RAW_IMU)' 'mag_field_motors(RAW_IMU,SENSOR_OFFSETS,(%f,%f,%f),SERVO_OUTPUT_RAW,(%f,%f,%f))'" % (
        filename, offsets.x, offsets.y, offsets.z, motor_ofs.x, motor_ofs.y,
        motor_ofs.z)
Exemplo n.º 23
0
def toVec(magnitude, angle):
    """Converts a magnitude and angle (radians) to a vector in the xy plane."""
    v = Vector3(magnitude, 0, 0)
    m = Matrix3()
    m.from_euler(0, 0, angle)
    return m.transposed() * v
Exemplo n.º 24
0
def earth_gyro(RAW_IMU, ATTITUDE):
    '''return earth frame gyro vector'''
    r = rotation(ATTITUDE)
    accel = Vector3(degrees(RAW_IMU.xgyro), degrees(RAW_IMU.ygyro),
                    degrees(RAW_IMU.zgyro)) * 0.001
    return r * accel
Exemplo n.º 25
0
def gps_velocity_body(GPS_RAW_INT, ATTITUDE):
    '''return GPS velocity vector in body frame'''
    r = rotation(ATTITUDE)
    return r.transposed() * Vector3(GPS_RAW_INT.vel*0.01*cos(radians(GPS_RAW_INT.cog*0.01)),
                                    GPS_RAW_INT.vel*0.01*sin(radians(GPS_RAW_INT.cog*0.01)),
                                    -tan(ATTITUDE.pitch)*GPS_RAW_INT.vel*0.01)
Exemplo n.º 26
0
    def update(self, servos):
        # how much time has passed?
        t = time.time()
        delta_time = t - self.last_time
        self.last_time = t

        # get swash proportions (these are from 0 to 1)
        swash1 = servos[0]
        swash2 = servos[1]
        swash3 = servos[2]
        tail_rotor = servos[3]
        rsc = servos[7]

        # get total thrust from 0 to 1
        thrust = (rsc / self.rsc_setpoint) * (swash1 + swash2 + swash3) / 3.0

        # very simplistic mapping to body euler rates
        roll_rate = swash1 - swash2
        pitch_rate = (swash1 + swash2) / 2.0 - swash3
        yaw_rate = tail_rotor - 0.5

        #print(swash1, swash2, swash3, roll_rate, pitch_rate, yaw_rate, thrust, rsc)

        roll_rate *= rsc / self.rsc_setpoint
        pitch_rate *= rsc / self.rsc_setpoint
        yaw_rate *= rsc / self.rsc_setpoint

        rot_accel = Vector3(roll_rate * self.roll_rate_max,
                            pitch_rate * self.pitch_rate_max,
                            yaw_rate * self.yaw_rate_max)

        # rotational air resistance
        rot_accel.x -= self.gyro.x * radians(
            5000.0) / self.terminal_rotation_rate
        rot_accel.y -= self.gyro.y * radians(
            5000.0) / self.terminal_rotation_rate
        rot_accel.z -= self.gyro.z * radians(
            5000.0) / self.terminal_rotation_rate

        # update rotational rates in body frame
        self.gyro += rot_accel * delta_time

        # update attitude
        self.dcm.rotate(self.gyro * delta_time)
        self.dcm.normalize()

        # air resistance
        air_resistance = -self.velocity * (self.gravity /
                                           self.terminal_velocity)

        thrust *= self.thrust_scale

        accel_body = Vector3(0, 0, -thrust / self.mass)
        accel_earth = self.dcm * accel_body
        accel_earth += Vector3(0, 0, self.gravity)
        accel_earth += air_resistance

        # if we're on the ground, then our vertical acceleration is limited
        # to zero. This effectively adds the force of the ground on the aircraft
        if self.on_ground() and accel_earth.z > 0:
            accel_earth.z = 0

        # work out acceleration as seen by the accelerometers. It sees the kinematic
        # acceleration (ie. real movement), plus gravity
        self.accel_body = self.dcm.transposed() * (
            accel_earth + Vector3(0, 0, -self.gravity))

        # new velocity vector
        self.velocity += accel_earth * delta_time

        # new position vector
        old_position = self.position.copy()
        self.position += self.velocity * delta_time

        # constrain height to the ground
        if self.on_ground():
            if not self.on_ground(old_position):
                print("Hit ground at %f m/s" % (self.velocity.z))

            self.velocity = Vector3(0, 0, 0)
            # zero roll/pitch, but keep yaw
            (r, p, y) = self.dcm.to_euler()
            self.dcm.from_euler(0, 0, y)

            self.position = Vector3(
                self.position.x, self.position.y,
                -(self.ground_level + self.frame_height - self.home_altitude))

        # update lat/lon/altitude
        self.update_position()
Exemplo n.º 27
0
 def __init__(self, roll, pitch, yaw):
     self.dcm = Matrix3()
     self.dcm2 = Matrix3()
     self.dcm.from_euler(radians(roll), radians(pitch), radians(yaw))
     self.dcm2.from_euler(radians(roll), radians(pitch), radians(yaw))
     self.mag = Vector3()
     self.gyro = Vector3()
     self.accel = Vector3()
     self.gps = None
     self.rate = 50.0
     self.kp = 0.2
     self.kp_yaw = 0.3
     self.omega_P = Vector3()
     self.omega_P_yaw = Vector3()
     self.omega_I = Vector3(
     )  # (-0.00199045287445, -0.00653007719666, -0.00714212376624)
     self.omega_I_sum = Vector3()
     self.omega_I_sum_time = 0
     self.omega = Vector3()
     self.ra_sum = Vector3()
     self.last_delta_angle = Vector3()
     self.last_velocity = Vector3()
     (self.roll, self.pitch, self.yaw) = self.dcm.to_euler()
     (self.roll2, self.pitch2, self.yaw2) = self.dcm2.to_euler()
Exemplo n.º 28
0
    def update(self, servos):

        # if in skid steering mode the steering and throttle values are used for motor1 and motor2
        if self.skid_steering:
            motor1 = 2 * (servos[0] - 0.5)
            motor2 = 2 * (servos[2] - 0.5)
            steering = motor1 - motor2
            throttle = 0.5 * (motor1 + motor2)
        else:
            steering = 2 * (servos[0] - 0.5)
            throttle = 2 * (servos[2] - 0.5)

        # how much time has passed?
        t = self.time_now
        delta_time = t - self.last_time
        self.last_time = t

        # speed in m/s in body frame
        velocity_body = self.dcm.transposed() * self.velocity

        # speed along x axis, +ve is forward
        speed = velocity_body.x

        # yaw rate in degrees/s
        yaw_rate = self.yaw_rate(steering, speed)

        # target speed with current throttle
        target_speed = throttle * self.max_speed

        # linear acceleration in m/s/s - very crude model
        accel = self.max_accel * (target_speed - speed) / self.max_speed

        #        print('speed=%f throttle=%f steering=%f yaw_rate=%f accel=%f' % (speed, state.throttle, state.steering, yaw_rate, accel))

        self.gyro = Vector3(0, 0, radians(yaw_rate))

        # update attitude
        self.dcm.rotate(self.gyro * delta_time)
        self.dcm.normalize()

        # accel in body frame due to motor
        accel_body = Vector3(accel, 0, 0)

        # add in accel due to direction change
        accel_body.y += radians(yaw_rate) * speed

        # now in earth frame
        accel_earth = self.dcm * accel_body
        accel_earth += Vector3(0, 0, self.gravity)

        # if we're on the ground, then our vertical acceleration is limited
        # to zero. This effectively adds the force of the ground on the aircraft
        accel_earth.z = 0

        # work out acceleration as seen by the accelerometers. It sees the kinematic
        # acceleration (ie. real movement), plus gravity
        self.accel_body = self.dcm.transposed() * (
            accel_earth + Vector3(0, 0, -self.gravity))

        # new velocity vector
        self.velocity += accel_earth * delta_time

        # new position vector
        old_position = self.position.copy()
        self.position += self.velocity * delta_time

        # update lat/lon/altitude
        self.update_position()
Exemplo n.º 29
0
def noise():
    '''a noise vector'''
    from random import gauss
    v = Vector3(gauss(0, 1), gauss(0, 1), gauss(0, 1))
    v.normalize()
    return v * opts.noise
Exemplo n.º 30
0
 def pos_cb(self, msg):
     self.velocity = Vector3(msg.vx, msg.vy, msg.vz)
     self.position = Vector3(msg.x, msg.y, msg.z)
     self.have_new_pos = True