int DMP::getAttitude()
{
  if (!dmpReady) return -1;

  // wait for FIFO count > 42 bits
  do {
  fifoCount = mpu.getFIFOCount();
  }while (fifoCount<42);

  if (fifoCount == 1024) {
    // reset so we can continue cleanly
    mpu.resetFIFO();
    printf("FIFO overflow!\n");

    return -1;

    // otherwise, check for DMP data ready interrupt
    //(this should happen frequently)
  } else  {
    //read packet from fifo
    mpu.getFIFOBytes(fifoBuffer, packetSize);

    mpu.dmpGetQuaternion(&q, fifoBuffer);
    mpu.dmpGetGravity(&gravity, &q);
    mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);


    for (int i=0;i<DIM;i++){
      //offset removal
      ypr[i]-=m_ypr_off[i];

      //scaling for output in degrees
      ypr[i]*=180/M_PI;
    }

    //printf(" %7.2f %7.2f %7.2f\n",ypr[0],ypr[1],ypr[2]);

    //unwrap yaw when it reaches 180
    ypr[0] = wrap_180(ypr[0]);

    //change sign of ROLL, MPU is attached upside down
    ypr[2]*=-1.0;

    mpu.dmpGetGyro(g, fifoBuffer);

    //0=gyroX, 1=gyroY, 2=gyroZ
    //swapped to match Yaw,Pitch,Roll
    //Scaled from deg/s to get tr/s
     for (int i=0;i<DIM;i++){
       gyro[i]   = (float)(g[DIM-i-1])/131.0/360.0;
     }

    // printf("gyro  %7.2f %7.2f %7.2f    \n", (float)g[0]/131.0,
    // 	   (float)g[1]/131.0,
    // 	   (float)g[2]/131.0);

     return 0;

  }
}
Exemple #2
0
ThrottleValues ModeStab::ComputeThrottle(float dt, const RCValues &rc, 
	float yaw, float pitch, float roll, 
	float omega_yaw, float omega_pitch, float omega_roll){
	
	float rcp = -map(rc.pitch, 1000, 2000, -45, 45); //(pitch - 1500.0); 
	float rcr =  map(rc.roll, 1000, 2000, -45, 45); //(roll - 1500.0); 
	float rcy = -map(rc.yaw, 1000, 2000, -50, 50); //(yaw - 1500.0); 
	
	// calculate desired rotation rate in degrees / sec
	float sp = mPID[PID_STAB_PITCH].get_pid(rcp - pitch, dt); 
	float sr = mPID[PID_STAB_ROLL].get_pid(rcr - roll, dt); 
	float sy = mPID[PID_STAB_YAW].get_pid(wrap_180(rcy - mTargetYaw), dt); 
	
	if(abs(rc.yaw - 1500) > 10){
		sy = rcy;  
		mTargetYaw = yaw; 
	} 
	
	// calculate the actual rate based on current gyro rate in degrees
	float rp = mPID[PID_RATE_PITCH	].get_pid(sp - omega_pitch, dt); 
	float rr = mPID[PID_RATE_ROLL		].get_pid(sr - omega_roll, dt); 
	float ry = mPID[PID_RATE_YAW		].get_pid(sy - omega_yaw, dt); 
	
	// H-copter control test
	/*
	return glm::i16vec4(
		// front left
				- rr - rp + ry,
		// back right
				+ rr + rp - ry,
		// back left 
				- rr + rp - ry,
		// front right
				+ rr - rp + ry);
	*/
	return glm::i16vec4(
		// front
				+ rp + ry,
		// back  
				- rp + ry,
		// left 
				+ rr - ry,
		// right
				- rr - ry
	); 
}
bool AP_Proximity_LightWareSF40C::convert_angle_to_sector(float angle_degrees, uint8_t &sector) const
{
    // sanity check angle
    if (angle_degrees > 360.0f || angle_degrees < -180.0f) {
        return false;
    }

    // convert to 0 ~ 360
    if (angle_degrees < 0.0f) {
        angle_degrees += 360.0f;
    }

    bool closest_found = false;
    uint8_t closest_sector;
    float closest_angle;

    // search for which sector angle_degrees falls into
    for (uint8_t i = 0; i < _num_sectors; i++) {
        float angle_diff = fabsf(wrap_180(_sector_middle_deg[i] - angle_degrees));

        // record if closest
        if (!closest_found || angle_diff < closest_angle) {
            closest_found = true;
            closest_sector = i;
            closest_angle = angle_diff;
        }

        if (fabsf(angle_diff) <= _sector_width_deg[i] / 2.0f) {
            sector = i;
            return true;
        }
    }

    // angle_degrees might have been within a gap between sectors
    if (closest_found) {
        sector = closest_sector;
        return true;
    }

    return false;
}
int ms_update() {
	if (!dmpReady) {
		printf("Error: DMP not ready!!\n");
		return -1;
	}

	while (dmp_read_fifo(g,a,_q,&sensors,&fifoCount)!=0); //gyro and accel can be null because of being disabled in the efeatures
	q = _q;
	GetGravity(&gravity, &q);
	GetYawPitchRoll(ypr, &q, &gravity);

	mpu_get_temperature(&t);
	temp=(float)t/65536L;

	mpu_get_compass_reg(c);

	//scaling for degrees output
	for (int i=0;i<DIM;i++){
		ypr[i]*=180/M_PI;
	}

	//unwrap yaw when it reaches 180
	ypr[0] = wrap_180(ypr[0]);

	//change sign of Pitch, MPU is attached upside down
	ypr[1]*=-1.0;

	//0=gyroX, 1=gyroY, 2=gyroZ
	//swapped to match Yaw,Pitch,Roll
	//Scaled from deg/s to get tr/s
	for (int i=0;i<DIM;i++){
		gyro[i]   = (float)(g[DIM-i-1])/131.0/360.0;
		accel[i]   = (float)(a[DIM-i-1]);
		compass[i] = (float)(c[DIM-i-1]);
	}

	return 0;
}
// rotate vector to correct for beacon system yaw orientation
Vector3f AP_Beacon_Backend::correct_for_orient_yaw(const Vector3f &vector)
{
    // exit immediately if no correction
    if (_frontend.orient_yaw == 0) {
        return vector;
    }

    // check for change in parameter value and update constants
    if (orient_yaw_deg != _frontend.orient_yaw) {
        _frontend.orient_yaw = wrap_180(_frontend.orient_yaw.get());

        // calculate rotation constants
        orient_yaw_deg = _frontend.orient_yaw;
        orient_cos_yaw = cosf(radians(orient_yaw_deg));
        orient_sin_yaw = sinf(radians(orient_yaw_deg));
    }

    // rotate x,y by -orient_yaw
    Vector3f vec_rotated;
    vec_rotated.x = vector.x*orient_cos_yaw - vector.y*orient_sin_yaw;
    vec_rotated.y = vector.x*orient_sin_yaw + vector.y*orient_cos_yaw;
    vec_rotated.z = vector.z;
    return vec_rotated;
}
// *Somehow* modified by me..
// Besides mwii credit must go to Sebbi, BRM! Hopefully they condone mentioning them above my trash.
// Sebbi for his rotation of the acc vector and BRM for his normalization ideas.
static void getEstimatedAttitude(void)
{
    static t_fp_vector EstG, EstM;
    static float    accLPFALT[3], accLPFGPS[3], Tilt_25deg, INVsens1G;
    static float    INV_GYR_CMPF_FACTOR, INV_GYR_CMPFM_FACTOR, ACC_GPS_RC, ACC_ALT_RC, ACC_RC;
    static uint32_t previousT, UpsDwnTimer;
    static bool     init = false;
    float           tmp[3], scale, deltaGyroAngle[3], ACCALTFac, ACCGPSFac, ACCFac, rollRAD, pitchRAD;
    float           NormFst = 0.0f, NormScnd, NormR, A, B, cr, sr, cp, sp, cy, sy, spcy, spsy, acc_south, acc_west, acc_up, FAC;
    uint8_t         i;
    uint32_t        tmpu32, currentT = micros();
    ACCDeltaTimeINS = (float)(currentT - previousT) * 0.000001f;
    previousT       = currentT;
    if(!init)                                                                 // Setup variables & constants
    {
        init = true;
        INVsens1G            = 1.0f / cfg.sens_1G;
        Tilt_25deg           = cosf(25.0f * RADX);
        INV_GYR_CMPF_FACTOR  = 1.0f / (float)(cfg.gy_cmpf  + 1);              // Default 400
        INV_GYR_CMPFM_FACTOR = 1.0f / (float)(cfg.gy_cmpfm + 1);              // Default 200
        ACC_ALT_RC           = 0.5f / (M_PI * cfg.acc_altlpfhz);              // Default 10 Hz
        ACC_RC               = 0.5f / (M_PI * cfg.acc_lpfhz);                 // Default 0,536 Hz
        ACC_GPS_RC           = 0.5f / (M_PI * cfg.acc_gpslpfhz);              // Default 5 Hz
        for (i = 0; i < 3; i++)                                               // Preset some values to reduce runup time
        {
            tmp[0]       = accADC[i] * INVsens1G;
            accSmooth[i] = tmp[0];
            accLPFGPS[i] = tmp[0];
            accLPFALT[i] = tmp[0];
            EstG.A[i]    = tmp[0] * 0.5f;
        }
    }
    ACCALTFac = ACCDeltaTimeINS / (ACC_ALT_RC + ACCDeltaTimeINS);             // Adjust LPF to cycle time / do Hz cut off
    ACCGPSFac = ACCDeltaTimeINS / (ACC_GPS_RC + ACCDeltaTimeINS);             // Adjust LPF to cycle time / do Hz cut off
    ACCFac    = ACCDeltaTimeINS / (ACC_RC     + ACCDeltaTimeINS);
    scale     = ACCDeltaTimeINS * GyroScale;                                  // SCALE CHANGED TO RAD per SECONDS, DAMN
    for (i = 0; i < 3; i++)
    {
        tmp[0]            = accADC[i]    *  INVsens1G;                        // Reference all to 1G here
        accLPFGPS[i]     += ACCGPSFac    * (tmp[0] - accLPFGPS[i]);           // For GPS
        accLPFALT[i]     += ACCALTFac    * (tmp[0] - accLPFALT[i]);           // For Althold
        accSmooth[i]     += ACCFac       * (tmp[0] - accSmooth[i]);           // For Gyrodrift correction
        NormFst          += accSmooth[i] *  accSmooth[i];
        deltaGyroAngle[i] = gyroADC[i]   *  scale;                            // deltaGyroAngle is in RAD
    }
    RotGravAndMag(&EstG.V, &EstM.V, deltaGyroAngle);                          // Rotate Grav&Mag together to avoid doublecalculation
    NormFst  = sqrtf(NormFst);
    tmpu32   = (uint32_t)(NormFst * 1000.0f);                                 // Make it "shorter" for comparison in temp variable
    NormScnd = sqrtf(EstG.A[0] * EstG.A[0] + EstG.A[1] * EstG.A[1] + EstG.A[2] * EstG.A[2]);
    if (NormScnd) NormR = 1.0f / NormScnd;
    else          NormR = INVsens1G;                                          // Feed vanilla value in that rare case, to let angle calculation always happen
    for (i = 0; i < 3; i++) tmp[i] = EstG.A[i] * NormR;                       // tmp[0..2] contains normalized EstG
    if (850 < tmpu32 && tmpu32 < 1150)                                        // Gyro drift correction if ACC between 0.85G and 1.15G else skip filter, as EstV already rotated by Gyro
    {
        NormR = 1.0f / NormFst;                                               // We just cmp filter together normalized vectors here. Div 0 not possible here.
        for (i = 0; i < 3; i++) EstG.A[i] = (tmp[i] * (float)cfg.gy_cmpf + accSmooth[i] * NormR) * INV_GYR_CMPF_FACTOR;
    }
    rollRAD      =  atan2f(tmp[0], tmp[2]);                                   // Note: One cycle after successful cmpf is done with old values.
    pitchRAD     =  asinf(-tmp[1]);                                           // Has to have the "wrong sign" relative to angle[PITCH]
    angle[ROLL]  =  rollRAD  * RADtoDEG10;                                    // Use rounded values, eliminate jitter for main PID I and D
    angle[PITCH] = -pitchRAD * RADtoDEG10;
    TiltValue    =  cosf(rollRAD) * cosf(pitchRAD);                           // We do this correctly here
    if (TiltValue >= 0)   UpsDwnTimer = 0;
    else if(!UpsDwnTimer) UpsDwnTimer = currentT + 20000;                     // Use Timer here to make absolutely sure we are upsidedown
    if (UpsDwnTimer && currentT > UpsDwnTimer) UpsideDown = true;
    else UpsideDown = false;
    if (TiltValue > Tilt_25deg) f.SMALL_ANGLES_25 = 1;
    else f.SMALL_ANGLES_25 = 0;
    cr = cosf(rollRAD);
    sr = sinf(rollRAD);
    cp = cosf(pitchRAD);
    sp = sinf(pitchRAD);
    if (cfg.mag_calibrated)                                                   // mag_calibrated can just be true if MAG present
    {
        NormFst = sqrtf(EstM.A[0] * EstM.A[0] + EstM.A[1] * EstM.A[1] + EstM.A[2] * EstM.A[2]);
        if (NormFst) NormR = 1.0f / NormFst;
        else         NormR = 1.0f;                                            // Vanilla value for rare case
        for (i = 0; i < 3; i++) tmp[i] = EstM.A[i] * NormR;                   // tmp[0..2] contains normalized EstM
        if(HaveNewMag)                                                        // Only do Complementary filter when new MAG data are available
        {
            HaveNewMag = false;
            NormFst = sqrtf(magADCfloat[0] * magADCfloat[0] + magADCfloat[1] * magADCfloat[1] + magADCfloat[2] * magADCfloat[2]);
            if (NormFst) NormR = 1.0f / NormFst;
            else         NormR = 1.0f;
            for (i = 0; i < 3; i++) EstM.A[i] = (tmp[i] * (float)cfg.gy_cmpfm + magADCfloat[i] * NormR) * INV_GYR_CMPFM_FACTOR;
        }
        A  = tmp[1] * cp + tmp[0] * sr * sp + tmp[2] * cr * sp;
        B  = tmp[0] * cr - tmp[2] * sr;
        heading = wrap_180(atan2f(-B, A) * RADtoDEG + magneticDeclination);   // Get rad to Degree and add declination (note: without *10) // Wrap to -180 0 +180 Degree
    } else heading = 0;                                                       // if no mag or not calibrated do bodyframe below
    tmp[0]    = heading * RADX;                                               // Do GPS INS rotate ACC X/Y to earthframe no centrifugal comp. yet
    cy        = cosf(tmp[0]);
    sy        = sinf(tmp[0]);
    cos_yaw_x = cy;                                                           // Store for general use
    sin_yaw_y = sy;                                                           // Store for general use
    spcy      = sp * cy;
    spsy      = sp * sy;
    FAC       = 980.665f * ACCDeltaTimeINS;                                   // vel factor for normalized output tmp3 = (9.80665f * (float)ACCDeltaTime) / 10000.0f;
    acc_up    = ((-sp) * accLPFALT[1] + sr * cp * accLPFALT[0] + cp * cr * accLPFALT[2]) - 1;// -1G
    if(GroundAltInitialized) vario += acc_up * FAC * constrain(TiltValue + 0.05, 0.5f, 1.0f);// Positive when moving Up. Just do Vario when Baro completely initialized. Empirical hightdrop reduction on tilt.
    acc_south = cp * cy * accLPFGPS[1] + (sr * spcy - cr * sy) * accLPFGPS[0] + ( sr * sy + cr * spcy) * accLPFGPS[2];
    acc_west  = cp * sy * accLPFGPS[1] + (cr * cy + sr * spsy) * accLPFGPS[0] + (-sr * cy + cr * spsy) * accLPFGPS[2];
    ACC_speed[LAT] -= acc_south * FAC;                                        // Positive when moving North cm/sec when no MAG this is speed to the front
    ACC_speed[LON] -= acc_west  * FAC;                                        // Positive when moving East cm/sec when no MAG this is speed to the right
}
/*
  update navigation for landing
 */
bool AP_Landing_Deepstall::verify_land(const Location &prev_WP_loc, Location &next_WP_loc, const Location &current_loc,
        const float height, const float sink_rate, const float wp_proportion, const uint32_t last_flying_ms,
        const bool is_armed, const bool is_flying, const bool rangefinder_state_in_range)
{
    switch (stage) {
    case DEEPSTALL_STAGE_FLY_TO_LANDING:
        if (get_distance(current_loc, landing_point) > fabsf(2 * landing.aparm.loiter_radius)) {
            landing.nav_controller->update_waypoint(current_loc, landing_point);
            return false;
        }
        stage = DEEPSTALL_STAGE_ESTIMATE_WIND;
        loiter_sum_cd = 0; // reset the loiter counter
        FALLTHROUGH;
    case DEEPSTALL_STAGE_ESTIMATE_WIND:
        {
        landing.nav_controller->update_loiter(landing_point, landing.aparm.loiter_radius, landing_point.flags.loiter_ccw ? -1 : 1);
        if (!landing.nav_controller->reached_loiter_target() || (fabsf(height) > DEEPSTALL_LOITER_ALT_TOLERANCE)) {
            // wait until the altitude is correct before considering a breakout
            return false;
        }
        // only count loiter progress when within the target altitude
        int32_t target_bearing = landing.nav_controller->target_bearing_cd();
        int32_t delta = wrap_180_cd(target_bearing - last_target_bearing);
        delta *= (landing_point.flags.loiter_ccw ? -1 : 1);
        if (delta > 0) { // only accumulate turns in the correct direction
            loiter_sum_cd += delta;
        }
        last_target_bearing = target_bearing;
        if (loiter_sum_cd < 36000) {
            // wait until we've done at least one complete loiter at the correct altitude
            return false;
        }
        stage = DEEPSTALL_STAGE_WAIT_FOR_BREAKOUT;
        loiter_sum_cd = 0; // reset the loiter counter
        FALLTHROUGH;
        }
    case DEEPSTALL_STAGE_WAIT_FOR_BREAKOUT:
        // rebuild the approach path if we have done less then a full circle to allow it to be
        // more into the wind as the estimator continues to refine itself, and allow better
        // compensation on windy days. This is limited to a single full circle though, as on
        // a no wind day you could be in this loop forever otherwise.
        if (loiter_sum_cd < 36000) {
            build_approach_path(false);
        }
        if (!verify_breakout(current_loc, arc_entry, height)) {
            int32_t target_bearing = landing.nav_controller->target_bearing_cd();
            int32_t delta = wrap_180_cd(target_bearing - last_target_bearing);
            if (delta > 0) { // only accumulate turns in the correct direction
                loiter_sum_cd += delta;
            }
            last_target_bearing = target_bearing;
            landing.nav_controller->update_loiter(landing_point, landing.aparm.loiter_radius, landing_point.flags.loiter_ccw ? -1 : 1);
            return false;
        }
        stage = DEEPSTALL_STAGE_FLY_TO_ARC;
        memcpy(&breakout_location, &current_loc, sizeof(Location));
        FALLTHROUGH;
    case DEEPSTALL_STAGE_FLY_TO_ARC:
        if (get_distance(current_loc, arc_entry) > 2 * landing.aparm.loiter_radius) {
            landing.nav_controller->update_waypoint(breakout_location, arc_entry);
            return false;
        }
        stage = DEEPSTALL_STAGE_ARC;
        FALLTHROUGH;
    case DEEPSTALL_STAGE_ARC:
        {
        Vector2f groundspeed = landing.ahrs.groundspeed_vector();
        if (!landing.nav_controller->reached_loiter_target() ||
            (fabsf(wrap_180(target_heading_deg -
                            degrees(atan2f(-groundspeed.y, -groundspeed.x) + M_PI))) >= 10.0f)) {
            landing.nav_controller->update_loiter(arc, landing.aparm.loiter_radius, landing_point.flags.loiter_ccw ? -1 : 1);
            return false;
        }
        stage = DEEPSTALL_STAGE_APPROACH;
        }
        FALLTHROUGH;
    case DEEPSTALL_STAGE_APPROACH:
        {
        Location entry_point;
        landing.nav_controller->update_waypoint(arc_exit, extended_approach);

        float relative_alt_D;
        landing.ahrs.get_relative_position_D_home(relative_alt_D);

        const float travel_distance = predict_travel_distance(landing.ahrs.wind_estimate(), -relative_alt_D, false);

        memcpy(&entry_point, &landing_point, sizeof(Location));
        location_update(entry_point, target_heading_deg + 180.0, travel_distance);

        if (!location_passed_point(current_loc, arc_exit, entry_point)) {
            if (location_passed_point(current_loc, arc_exit, extended_approach)) {
                // this should never happen, but prevent against an indefinite fly away
                stage = DEEPSTALL_STAGE_FLY_TO_LANDING;
            }
            return false;
        }
        predict_travel_distance(landing.ahrs.wind_estimate(), -relative_alt_D, true);
        stage = DEEPSTALL_STAGE_LAND;
        stall_entry_time = AP_HAL::millis();

        const SRV_Channel* elevator = SRV_Channels::get_channel_for(SRV_Channel::k_elevator);
        if (elevator != nullptr) {
            // take the last used elevator angle as the starting deflection
            // don't worry about bailing here if the elevator channel can't be found
            // that will be handled within override_servos
            initial_elevator_pwm = elevator->get_output_pwm();
        }
        }
        FALLTHROUGH;
    case DEEPSTALL_STAGE_LAND:
        // while in deepstall the only thing verify needs to keep the extended approach point sufficently far away
        landing.nav_controller->update_waypoint(current_loc, extended_approach);
        landing.disarm_if_autoland_complete_fn();
        return false;
    default:
        return true;
    }
}
/*
  steering rate controller. Returns servo out -4500 to 4500 given
  desired yaw rate in degrees/sec. Positive yaw rate means clockwise yaw.
*/
int32_t AP_SteerController::get_steering_out_rate(float desired_rate)
{
	uint32_t tnow = AP_HAL::millis();
	uint32_t dt = tnow - _last_t;
	if (_last_t == 0 || dt > 1000) {
		dt = 0;
	}
	_last_t = tnow;

    float speed = _ahrs.groundspeed();
    if (speed < _minspeed) {
        // assume a minimum speed. This stops osciallations when first starting to move
        speed = _minspeed;
    }

    // this is a linear approximation of the inverse steering
    // equation for a ground vehicle. It returns steering as an angle from -45 to 45
    float scaler = 1.0f / speed;

    _pid_info.desired = desired_rate;

	// Calculate the steering rate error (deg/sec) and apply gain scaler
    // We do this in earth frame to allow for rover leaning over in hard corners
    float yaw_rate_earth = ToDeg(_ahrs.get_yaw_rate_earth());
    if (_reverse) {
        yaw_rate_earth = wrap_180(180 + yaw_rate_earth);
    }
    float rate_error = (desired_rate - yaw_rate_earth) * scaler;
	
	// Calculate equivalent gains so that values for K_P and K_I can be taken across from the old PID law
    // No conversion is required for K_D
	float ki_rate = _K_I * _tau * 45.0f;
	float kp_ff = MAX((_K_P - _K_I * _tau) * _tau  - _K_D , 0) * 45.0f;
	float k_ff = _K_FF * 45.0f;
	float delta_time    = (float)dt * 0.001f;
	
	// Multiply roll rate error by _ki_rate and integrate
	// Don't integrate if in stabilise mode as the integrator will wind up against the pilots inputs
	if (ki_rate > 0 && speed >= _minspeed) {
		// only integrate if gain and time step are positive.
		if (dt > 0) {
		    float integrator_delta = rate_error * ki_rate * delta_time * scaler;
			// prevent the integrator from increasing if steering defln demand is above the upper limit
			if (_last_out < -45) {
                integrator_delta = MAX(integrator_delta , 0);
            } else if (_last_out > 45) {
                // prevent the integrator from decreasing if steering defln demand is below the lower limit
                integrator_delta = MIN(integrator_delta, 0);
            }
			_pid_info.I += integrator_delta;
		}
	} else {
		_pid_info.I = 0;
	}
	
    // Scale the integration limit
    float intLimScaled = _imax * 0.01f;

    // Constrain the integrator state
    _pid_info.I = constrain_float(_pid_info.I, -intLimScaled, intLimScaled);

    _pid_info.D = rate_error * _K_D * 4.0f; 
    _pid_info.P = (ToRad(desired_rate) * kp_ff) * scaler;
    _pid_info.FF = (ToRad(desired_rate) * k_ff) * scaler;
	
	// Calculate the demanded control surface deflection
	_last_out = _pid_info.D + _pid_info.FF + _pid_info.P + _pid_info.I;
	
	// Convert to centi-degrees and constrain
	return constrain_float(_last_out * 100, -4500, 4500);
}
Exemple #9
0
static void getEstimatedAttitude(void)
{
    static t_fp_vector EstG, EstM;
    static float    cms[3] = {0.0f, 0.0f, 0.0f}, Tilt_25deg, AccScaleCMSS;
    static float    INV_GY_CMPF, INV_GY_CMPFM, ACC_GPS_RC, ACC_ALT_RC, ACC_RC;
    static uint32_t UpsDwnTimer, SQ1G;
    static bool     init = false;
    float           tmp[3], DeltGyRad[3], rollRAD, pitchRAD;
    float           Norm, A, B, cr, sr, cp, sp, spcy, spsy, accycp, CmsFac;
    uint8_t         i;
    uint32_t        tmpu32 = 0;
    if(!init)                                                                 // Setup variables & constants
    {
        init = true;
        AccScaleCMSS = OneGcmss / (float)cfg.sens_1G;                         // scale to cm/ss
        SQ1G         = (int32_t)cfg.sens_1G * (int32_t)cfg.sens_1G;
        Tilt_25deg   = cosf(25.0f * RADX);
        INV_GY_CMPF  = 1.0f / (float)(cfg.gy_gcmpf + 1);                      // Default 400
        INV_GY_CMPFM = 1.0f / (float)(cfg.gy_mcmpf + 1);                      // Default 200
        tmp[0]       = 0.5f / M_PI;
        ACC_RC       = tmp[0] / cfg.acc_lpfhz;                                // Default 0,536 Hz
        ACC_ALT_RC   = tmp[0] / (float)cfg.acc_altlpfhz;                      // Default 10 Hz
        ACC_GPS_RC   = tmp[0] / (float)cfg.acc_gpslpfhz;                      // Default 5 Hz
        for (i = 0; i < 3; i++)                                               // Preset some values to reduce runup time
        {
            accSmooth[i] = accADC[i];
            EstG.A[i]    = accSmooth[i];
            EstM.A[i]    = magADCfloat[i];                                    // Using /2 for more stability
        }
    }
    CmsFac = ACCDeltaTimeINS * AccScaleCMSS;                                  // We need that factor for INS below
    tmp[0] = ACCDeltaTimeINS / (ACC_RC + ACCDeltaTimeINS);
    for (i = 0; i < 3; i++)
    {
        accSmooth[i] += tmp[0] * (accADC[i] - accSmooth[i]);                  // For Gyrodrift correction
        DeltGyRad[i]  = (ACCDeltaTimeINS * gyroADC[i]) * 0.0625f;             // gyroADC delivered in 16 * rad/s
        tmpu32       += (int32_t)accSmooth[i] * (int32_t)accSmooth[i];        // Accumulate ACC magnitude there
    }
    RotGravAndMag(&EstG.V, &EstM.V, DeltGyRad);                               // Rotate Grav & Mag together to avoid doublecalculation
    tmpu32 = (tmpu32 * 100) / SQ1G;                                           // accMag * 100 / ((int32_t)acc_1G * acc_1G);
    if (72 < tmpu32 && tmpu32 < 133)                                          // Gyro drift correct between 0.85G - 1.15G
    {
        for (i = 0; i < 3; i++) EstG.A[i] = (EstG.A[i] * (float)cfg.gy_gcmpf + accSmooth[i]) * INV_GY_CMPF;
    }
    tmp[0]       = EstG.A[0] * EstG.A[0] + EstG.A[2] * EstG.A[2];             // Start Angle Calculation. tmp[0] is used for heading below
    Norm         = sqrtf(tmp[0] + EstG.A[1] * EstG.A[1]);
    if(!Norm) return;                                                         // Should never happen but break here to prevent div-by-zero-evil
    Norm         = 1.0f / Norm;
    rollRAD      =  atan2f(EstG.A[0] * Norm, EstG.A[2] * Norm);               // Norm seems to be obsolete, but testing shows different result :)
    pitchRAD     = -asinf(constrain(EstG.A[1] * Norm, -1.0f, 1.0f));          // Ensure range, eliminate rounding stuff that might occure.
    cr           = cosf(rollRAD);
    sr           = sinf(rollRAD);
    cp           = cosf(pitchRAD);
    sp           = sinf(pitchRAD);
    TiltValue    = cr * cp;                                                   // We do this correctly here
    angle[ROLL]  = (float)((int32_t)( rollRAD  * RADtoDEG10 + 0.5f));         // Use rounded values, eliminate jitter for main PID I and D
    angle[PITCH] = (float)((int32_t)(-pitchRAD * RADtoDEG10 + 0.5f));
    if (TiltValue >= 0)   UpsDwnTimer = 0;
    else if(!UpsDwnTimer) UpsDwnTimer = currentTime + 20000;                  // Use 20ms Timer here to make absolutely sure we are upsidedown
    if (UpsDwnTimer && currentTime > UpsDwnTimer) UpsideDown = true;
    else UpsideDown = false;
    if (TiltValue > Tilt_25deg) f.SMALL_ANGLES_25 = 1;
    else f.SMALL_ANGLES_25 = 0;
    if (cfg.mag_calibrated)                                                   // mag_calibrated can just be true if MAG present
    {
        if(HaveNewMag)                                                        // Only do Complementary filter when new MAG data are available
        {
            HaveNewMag = false;
            for (i = 0; i < 3; i++) EstM.A[i] = (EstM.A[i] * (float)cfg.gy_mcmpf + magADCfloat[i]) * INV_GY_CMPFM;
        }
        A = EstM.A[1] * tmp[0] - (EstM.A[0] * EstG.A[0] + EstM.A[2] * EstG.A[2]) * EstG.A[1];// Mwii method is more precise (less rounding errors)
        B = EstM.A[2] * EstG.A[0] - EstM.A[0] * EstG.A[2];
        heading = wrap_180(atan2f(B, A * Norm) * RADtoDEG + magneticDeclination);
        if (sensors(SENSOR_GPS) && !UpsideDown)
        {
            tmp[0]    = heading * RADX;                                       // Do GPS INS rotate ACC X/Y to earthframe no centrifugal comp. yet
            cos_yaw_x = cosf(tmp[0]);                                         // Store for general use
            sin_yaw_y = sinf(tmp[0]);
            spcy      = sp * cos_yaw_x;
            spsy      = sp * sin_yaw_y;
            accycp    = cp * accADC[1];
            tmp[0]    = accycp * cos_yaw_x + (sr * spcy - cr * sin_yaw_y) * accADC[0] + ( sr * sin_yaw_y + cr * spcy) * accADC[2]; // Rotate raw acc here
            tmp[1]    = accycp * sin_yaw_y + (cr * cos_yaw_x + sr * spsy) * accADC[0] + (-sr * cos_yaw_x + cr * spsy) * accADC[2];
            tmp[2]    = ACCDeltaTimeINS / (ACC_GPS_RC + ACCDeltaTimeINS);
            for (i = 0; i < 2; i++)
            {
                cms[i]       += tmp[2] * (tmp[i] * CmsFac - cms[i]);
                ACC_speed[i] -= cms[i];                                       //cm/s N+ E+
            }
        }
    }
    if(GroundAltInitialized && !UpsideDown)                                   // GroundAltInitialized can just be true if baro present
    {
        tmp[0]  = ((-sp) * accADC[1] + sr * cp * accADC[0] + cp * cr * accADC[2]) - (float)cfg.sens_1G;
        cms[2] += (ACCDeltaTimeINS / (ACC_ALT_RC + ACCDeltaTimeINS)) * (tmp[0] * CmsFac - cms[2]);
        vario  += cms[2];
    }
}
Exemple #10
0
void loop() 
{
    static float yaw_target = 0;  
    // Wait until new orientation data (normally 5ms max)
    while (ins.num_samples_available() == 0);

    static uint32_t lastPkt = 0;

    static int16_t channels[8] = {0,0,0,0,0,0,0,0};
     
    Iriss::Command doSomething = check_for_command();
    do_respond(doSomething, channels);
     
    // turn throttle off if no update for 0.5seconds
    if(hal.scheduler->millis() - lastPkt > 500) {
        channels[2] = 0;
    }

    long rcthr, rcyaw, rcpit, rcroll;  // Variables to store radio in 

    // Read RC transmitter 
    rcthr = channels[2];
    rcyaw = channels[3];
    rcpit = channels[1];
    rcroll = channels[0];

    // Ask MPU6050 for orientation
    ins.update();
    float roll,pitch,yaw;  
    ins.quaternion.to_euler(&roll, &pitch, &yaw);
    roll = ToDeg(roll) ;
    pitch = ToDeg(pitch) ;
    yaw = ToDeg(yaw) ;

    // Ask MPU6050 for gyro data
    Vector3f gyro = ins.get_gyro();
    float gyroPitch = ToDeg(gyro.y), gyroRoll = ToDeg(gyro.x), gyroYaw = ToDeg(gyro.z);

    // Do the magic
    if(rcthr > RC_THR_MIN + 100) {  // Throttle raised, turn on stablisation.
        // Stablise PIDS
        float pitch_stab_output = constrain(pids[PID_PITCH_STAB].get_pid((float)rcpit - pitch, 1), -250, 250); 
        float roll_stab_output = constrain(pids[PID_ROLL_STAB].get_pid((float)rcroll - roll, 1), -250, 250);
        float yaw_stab_output = constrain(pids[PID_YAW_STAB].get_pid(wrap_180(yaw_target - yaw), 1), -360, 360);

        // is pilot asking for yaw change - if so feed directly to rate pid (overwriting yaw stab output)
        if(abs(rcyaw ) > 5) {
            yaw_stab_output = rcyaw;
            yaw_target = yaw;   // remember this yaw for when pilot stops
        }

        // rate PIDS
        long pitch_output =  (long) constrain(pids[PID_PITCH_RATE].get_pid(pitch_stab_output - gyroPitch, 1), - 500, 500);  
        long roll_output =  (long) constrain(pids[PID_ROLL_RATE].get_pid(roll_stab_output - gyroRoll, 1), -500, 500);  
        long yaw_output =  (long) constrain(pids[PID_ROLL_RATE].get_pid(yaw_stab_output - gyroYaw, 1), -500, 500);  

        // mix pid outputs and send to the motors.
        hal.rcout->write(MOTOR_FL, rcthr + roll_output + pitch_output - yaw_output);
        hal.rcout->write(MOTOR_BL, rcthr + roll_output - pitch_output + yaw_output);
        hal.rcout->write(MOTOR_FR, rcthr - roll_output + pitch_output + yaw_output);
        hal.rcout->write(MOTOR_BR, rcthr - roll_output - pitch_output - yaw_output);
    }
    else {
        // motors off
        hal.rcout->write(MOTOR_FL, 1000);
        hal.rcout->write(MOTOR_BL, 1000);
        hal.rcout->write(MOTOR_FR, 1000);
        hal.rcout->write(MOTOR_BR, 1000);
           
        // reset yaw target so we maintain this on takeoff
        yaw_target = yaw;

        // reset PID integrals whilst on the ground
        for(int i=0; i<6; i++) {
            pids[i].reset_I();
        }

    }
}