Example #1
0
/*
 * From Roll-Pitch Gyro Drift Compensation, Rev 3. William Premerlani, 2012.
 */
static void rollPitch_drift_GPS(float Rbe[3][3], float accels_e_int[3],
								 float delT_between_updates, float *errRollPitch_b)
{
	float errRollPitch_e[3];
	float dGPSdt_e[3];
	
	GPSVelocityData gpsVelocity;
	GPSVelocityGet(&gpsVelocity);
	
	dGPSdt_e[0] = (gpsVelocity.North - drft->GPSV_old[0]) / delT_between_updates;
	dGPSdt_e[1] = (gpsVelocity.East - drft->GPSV_old[1]) / delT_between_updates;
	dGPSdt_e[2] = -GRAVITY + (gpsVelocity.Down - drft->GPSV_old[2]) / delT_between_updates;
	
	drft->GPSV_old[0] = gpsVelocity.North;
	drft->GPSV_old[1] = gpsVelocity.East;
	drft->GPSV_old[2] = gpsVelocity.Down;
	
	float normdGPSdt_e = VectorMagnitude(dGPSdt_e);
	
	//Take cross product of integrated accelerometer measurements with integrated earth frame accelerations. We should be using normalized dGPSdt, but we perform that calculation in the following line(s).
	CrossProduct((const float *)accels_e_int, (const float *)dGPSdt_e, errRollPitch_e);
	
	//Scale cross product
	errRollPitch_e[0] /= (normdGPSdt_e * delT_between_updates);
	errRollPitch_e[1] /= (normdGPSdt_e * delT_between_updates);
	errRollPitch_e[2] /= (normdGPSdt_e * delT_between_updates);
	
	//Rotate earth drift error back into body frame;
	rot_mult(Rbe, errRollPitch_e, errRollPitch_b, FALSE);
}
Example #2
0
/**
 * @brief Apply calibration and rotation to the raw gyro data
 * @param[in] gyros The raw gyro data
 */
static void update_gyros(struct pios_sensor_gyro_data *gyros, GyrosData * gyrosData)
{
    static float gyro_temp_bias[3] = {0,0,0};

    // Scale the gyros
    float gyros_out[3] = {gyros->x * sensorSettings.GyroScale[0],
                          gyros->y * sensorSettings.GyroScale[1],
                          gyros->z * sensorSettings.GyroScale[2]
                         };

    // Update the bias due to the temperature
    updateTemperatureComp(gyrosData->temperature, gyro_temp_bias);

    // Apply temperature bias correction before the rotation
    if (bias_correct_gyro) {
        gyros_out[0] -= gyro_temp_bias[0];
        gyros_out[1] -= gyro_temp_bias[1];
        gyros_out[2] -= gyro_temp_bias[2];
    }

    // When computing the bias accumulate samples
    accumulate_gyro(gyros_out);


    if (rotate) {
        float gyros[3];
        rot_mult(Rsb, gyros_out, gyros, true);
        gyrosData->x = gyros[0];
        gyrosData->y = gyros[1];
        gyrosData->z = gyros[2];
    } else {
        gyrosData->x = gyros_out[0];
        gyrosData->y = gyros_out[1];
        gyrosData->z = gyros_out[2];
    }

    if(bias_correct_gyro) {
        // Applying integral component here so it can be seen on the gyros and correct bias
        gyrosData->x -= gyro_correct_int[0];
        gyrosData->y -= gyro_correct_int[1];
        gyrosData->z -= gyro_correct_int[2];
    }

    // Because most crafts wont get enough information from gravity to zero yaw gyro, we try
    // and make it average zero (weakly)
    gyro_correct_int[2] += gyrosData->z * yawBiasRate;

    gyrosData->temperature = gyros->temperature;
}
Example #3
0
void auxmagsupport_publish_samples(float mags[3], uint8_t status)
{
    float mag_out[3];

    mags[0] -= mag_bias[0];
    mags[1] -= mag_bias[1];
    mags[2] -= mag_bias[2];
    rot_mult(mag_transform, mags, mag_out);

    AuxMagSensorData data;
    data.x = mag_out[0];
    data.y = mag_out[1];
    data.z = mag_out[2];
    data.Status = status;
    AuxMagSensorSet(&data);
}
Example #4
0
/**
 * @brief Apply calibration and rotation to the raw accel data
 * @param[in] accels The raw accel data
 */
static void update_accels(struct pios_sensor_accel_data *accels, AccelsData * accelsData)
{
    // Average and scale the accels before rotation
    float accels_out[3] = {accels->x * sensorSettings.AccelScale[0] - sensorSettings.AccelBias[0],
                           accels->y * sensorSettings.AccelScale[1] - sensorSettings.AccelBias[1],
                           accels->z * sensorSettings.AccelScale[2] - sensorSettings.AccelBias[2]
                          };

    if (rotate) {
        float accel_rotated[3];
        rot_mult(Rsb, accels_out, accel_rotated, true);
        accelsData->x = accel_rotated[0];
        accelsData->y = accel_rotated[1];
        accelsData->z = accel_rotated[2];
    } else {
        accelsData->x = accels_out[0];
        accelsData->y = accels_out[1];
        accelsData->z = accels_out[2];
    }

    accelsData->temperature = accels->temperature;
}
Example #5
0
static void SensorsTask(void *parameters)
{
	portTickType lastSysTime;
	uint32_t accel_samples = 0;
	uint32_t gyro_samples = 0;
	int32_t accel_accum[3] = {0, 0, 0};
	int32_t gyro_accum[3] = {0,0,0};
	float gyro_scaling = 0;
	float accel_scaling = 0;
	static int32_t timeval;

	AlarmsClear(SYSTEMALARMS_ALARM_SENSORS);

	UAVObjEvent ev;
	settingsUpdatedCb(&ev);

	const struct pios_board_info * bdinfo = &pios_board_info_blob;	

	switch(bdinfo->board_rev) {
		case 0x01:
#if defined(PIOS_INCLUDE_L3GD20)
			gyro_test = PIOS_L3GD20_Test();
#endif
#if defined(PIOS_INCLUDE_BMA180)
			accel_test = PIOS_BMA180_Test();
#endif
			break;
		case 0x02:
#if defined(PIOS_INCLUDE_MPU6000)
			gyro_test = PIOS_MPU6000_Test();
			accel_test = gyro_test;
#endif
			break;
		default:
			PIOS_DEBUG_Assert(0);
	}

#if defined(PIOS_INCLUDE_HMC5883)
	mag_test = PIOS_HMC5883_Test();
#else
	mag_test = 0;
#endif

	if(accel_test < 0 || gyro_test < 0 || mag_test < 0) {
		AlarmsSet(SYSTEMALARMS_ALARM_SENSORS, SYSTEMALARMS_ALARM_CRITICAL);
		while(1) {
			PIOS_WDG_UpdateFlag(PIOS_WDG_SENSORS);
			vTaskDelay(10);
		}
	}
	
	// Main task loop
	lastSysTime = xTaskGetTickCount();
	bool error = false;
	uint32_t mag_update_time = PIOS_DELAY_GetRaw();
	while (1) {
		// TODO: add timeouts to the sensor reads and set an error if the fail
		sensor_dt_us = PIOS_DELAY_DiffuS(timeval);
		timeval = PIOS_DELAY_GetRaw();

		if (error) {
			PIOS_WDG_UpdateFlag(PIOS_WDG_SENSORS);
			lastSysTime = xTaskGetTickCount();
			vTaskDelayUntil(&lastSysTime, SENSOR_PERIOD / portTICK_RATE_MS);
			AlarmsSet(SYSTEMALARMS_ALARM_SENSORS, SYSTEMALARMS_ALARM_CRITICAL);
			error = false;
		} else {
			AlarmsClear(SYSTEMALARMS_ALARM_SENSORS);
		}


		for (int i = 0; i < 3; i++) {
			accel_accum[i] = 0;
			gyro_accum[i] = 0;
		}
		accel_samples = 0;
		gyro_samples = 0;

		AccelsData accelsData;
		GyrosData gyrosData;

		switch(bdinfo->board_rev) {
			case 0x01:  // L3GD20 + BMA180 board
#if defined(PIOS_INCLUDE_BMA180)
			{
				struct pios_bma180_data accel;
				
				int32_t read_good;
				int32_t count;
				
				count = 0;
				while((read_good = PIOS_BMA180_ReadFifo(&accel)) != 0 && !error)
					error = ((xTaskGetTickCount() - lastSysTime) > SENSOR_PERIOD) ? true : error;
				if (error) {
					// Unfortunately if the BMA180 ever misses getting read, then it will not
					// trigger more interrupts.  In this case we must force a read to kickstarts
					// it.
					struct pios_bma180_data data;
					PIOS_BMA180_ReadAccels(&data);
					continue;
				}
				while(read_good == 0) {	
					count++;
					
					accel_accum[1] += accel.x;
					accel_accum[0] += accel.y;
					accel_accum[2] -= accel.z;
					
					read_good = PIOS_BMA180_ReadFifo(&accel);
				}
				accel_samples = count;
				accel_scaling = PIOS_BMA180_GetScale();
				
				// Get temp from last reading
				accelsData.temperature = 25.0f + ((float) accel.temperature - 2.0f) / 2.0f;
			}
#endif
#if defined(PIOS_INCLUDE_L3GD20)
			{
				struct pios_l3gd20_data gyro;
				gyro_samples = 0;
				xQueueHandle gyro_queue = PIOS_L3GD20_GetQueue();
				
				if(xQueueReceive(gyro_queue, (void *) &gyro, 4) == errQUEUE_EMPTY) {
					error = true;
					continue;
				}
				
				gyro_samples = 1;
				gyro_accum[1] += gyro.gyro_x;
				gyro_accum[0] += gyro.gyro_y;
				gyro_accum[2] -= gyro.gyro_z;
				
				gyro_scaling = PIOS_L3GD20_GetScale();

				// Get temp from last reading
				gyrosData.temperature = gyro.temperature;
			}
#endif
				break;
			case 0x02:  // MPU6000 board
			case 0x03:  // MPU6000 board
#if defined(PIOS_INCLUDE_MPU6000)
			{
				struct pios_mpu6000_data mpu6000_data;
				xQueueHandle queue = PIOS_MPU6000_GetQueue();
				
				while(xQueueReceive(queue, (void *) &mpu6000_data, gyro_samples == 0 ? 10 : 0) != errQUEUE_EMPTY)
				{
					gyro_accum[0] += mpu6000_data.gyro_x;
					gyro_accum[1] += mpu6000_data.gyro_y;
					gyro_accum[2] += mpu6000_data.gyro_z;

					accel_accum[0] += mpu6000_data.accel_x;
					accel_accum[1] += mpu6000_data.accel_y;
					accel_accum[2] += mpu6000_data.accel_z;

					gyro_samples ++;
					accel_samples ++;
				}
				
				if (gyro_samples == 0) {
					PIOS_MPU6000_ReadGyros(&mpu6000_data);
					error = true;
					continue;
				}

				gyro_scaling = PIOS_MPU6000_GetScale();
				accel_scaling = PIOS_MPU6000_GetAccelScale();

				gyrosData.temperature = 35.0f + ((float) mpu6000_data.temperature + 512.0f) / 340.0f;
				accelsData.temperature = 35.0f + ((float) mpu6000_data.temperature + 512.0f) / 340.0f;
			}
#endif /* PIOS_INCLUDE_MPU6000 */
				break;
			default:
				PIOS_DEBUG_Assert(0);
		}

		// Scale the accels
		float accels[3] = {(float) accel_accum[0] / accel_samples, 
		                   (float) accel_accum[1] / accel_samples,
		                   (float) accel_accum[2] / accel_samples};
		float accels_out[3] = {accels[0] * accel_scaling * accel_scale[0] - accel_bias[0],
		                       accels[1] * accel_scaling * accel_scale[1] - accel_bias[1],
		                       accels[2] * accel_scaling * accel_scale[2] - accel_bias[2]};
		if (rotate) {
			rot_mult(R, accels_out, accels);
			accelsData.x = accels[0];
			accelsData.y = accels[1];
			accelsData.z = accels[2];
		} else {
			accelsData.x = accels_out[0];
			accelsData.y = accels_out[1];
			accelsData.z = accels_out[2];
		}
		AccelsSet(&accelsData);

		// Scale the gyros
		float gyros[3] = {(float) gyro_accum[0] / gyro_samples,
		                  (float) gyro_accum[1] / gyro_samples,
		                  (float) gyro_accum[2] / gyro_samples};
		float gyros_out[3] = {gyros[0] * gyro_scaling,
		                      gyros[1] * gyro_scaling,
		                      gyros[2] * gyro_scaling};
		if (rotate) {
			rot_mult(R, gyros_out, gyros);
			gyrosData.x = gyros[0];
			gyrosData.y = gyros[1];
			gyrosData.z = gyros[2];
		} else {
			gyrosData.x = gyros_out[0];
			gyrosData.y = gyros_out[1];
			gyrosData.z = gyros_out[2];
		}
		
		if (bias_correct_gyro) {
			// Apply bias correction to the gyros from the state estimator
			GyrosBiasData gyrosBias;
			GyrosBiasGet(&gyrosBias);
			gyrosData.x -= gyrosBias.x;
			gyrosData.y -= gyrosBias.y;
			gyrosData.z -= gyrosBias.z;
		}
		GyrosSet(&gyrosData);
		
		// Because most crafts wont get enough information from gravity to zero yaw gyro, we try
		// and make it average zero (weakly)

#if defined(PIOS_INCLUDE_HMC5883)
		MagnetometerData mag;
		if (PIOS_HMC5883_NewDataAvailable() || PIOS_DELAY_DiffuS(mag_update_time) > 150000) {
			int16_t values[3];
			PIOS_HMC5883_ReadMag(values);
			float mags[3] = {-(float) values[1] * mag_scale[0] - mag_bias[0],
			                 -(float) values[0] * mag_scale[1] - mag_bias[1],
			                 -(float) values[2] * mag_scale[2] - mag_bias[2]};
			if (rotate) {
				float mag_out[3];
				rot_mult(R, mags, mag_out);
				mag.x = mag_out[0];
				mag.y = mag_out[1];
				mag.z = mag_out[2];
			} else {
				mag.x = mags[0];
				mag.y = mags[1];
				mag.z = mags[2];
			}
			
			// Correct for mag bias and update if the rate is non zero
			if(cal.MagBiasNullingRate > 0)
				magOffsetEstimation(&mag);

			MagnetometerSet(&mag);
			mag_update_time = PIOS_DELAY_GetRaw();
		}
#endif

		PIOS_WDG_UpdateFlag(PIOS_WDG_SENSORS);

		lastSysTime = xTaskGetTickCount();
	}
}
Example #6
0
static void updateSensors(AttitudeRawData * attitudeRaw)
{
	struct pios_adxl345_data accel_data;
	float gyro[4];

	// Only wait the time for two nominal updates before setting an alarm
	if(xQueueReceive(gyro_queue, (void * const) gyro, UPDATE_RATE * 2) == errQUEUE_EMPTY) {
		AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE, SYSTEMALARMS_ALARM_ERROR);
		return;
	}


	// First sample is temperature
	attitudeRaw->gyros[ATTITUDERAW_GYROS_X] = -(gyro[1] - GYRO_NEUTRAL) * gyroGain;
	attitudeRaw->gyros[ATTITUDERAW_GYROS_Y] = (gyro[2] - GYRO_NEUTRAL) * gyroGain;
	attitudeRaw->gyros[ATTITUDERAW_GYROS_Z] = -(gyro[3] - GYRO_NEUTRAL) * gyroGain;

	int32_t x = 0;
	int32_t y = 0;
	int32_t z = 0;
	uint8_t i = 0;
	uint8_t samples_remaining;
	do {
		i++;
		samples_remaining = PIOS_ADXL345_Read(&accel_data);
		x +=  accel_data.x;
		y += -accel_data.y;
		z += -accel_data.z;
	} while ( (i < 32) && (samples_remaining > 0) );
	attitudeRaw->gyrotemp[0] = samples_remaining;
	attitudeRaw->gyrotemp[1] = i;

	float accel[3] = {(float) x / i, (float) y / i, (float) z / i};

	if(rotate) {
		// TODO: rotate sensors too so stabilization is well behaved
		float vec_out[3];
		rot_mult(R, accel, vec_out);
		attitudeRaw->accels[0] = vec_out[0];
		attitudeRaw->accels[1] = vec_out[1];
		attitudeRaw->accels[2] = vec_out[2];
		rot_mult(R, attitudeRaw->gyros, vec_out);
		attitudeRaw->gyros[0] = vec_out[0];
		attitudeRaw->gyros[1] = vec_out[1];
		attitudeRaw->gyros[2] = vec_out[2];
	} else {
		attitudeRaw->accels[0] = accel[0];
		attitudeRaw->accels[1] = accel[1];
		attitudeRaw->accels[2] = accel[2];
	}

	// Scale accels and correct bias
	attitudeRaw->accels[ATTITUDERAW_ACCELS_X] = (attitudeRaw->accels[ATTITUDERAW_ACCELS_X] - accelbias[0]) * 0.004f * 9.81f;
	attitudeRaw->accels[ATTITUDERAW_ACCELS_Y] = (attitudeRaw->accels[ATTITUDERAW_ACCELS_Y] - accelbias[1]) * 0.004f * 9.81f;
	attitudeRaw->accels[ATTITUDERAW_ACCELS_Z] = (attitudeRaw->accels[ATTITUDERAW_ACCELS_Z] - accelbias[2]) * 0.004f * 9.81f;

	if(bias_correct_gyro) {
		// Applying integral component here so it can be seen on the gyros and correct bias
		attitudeRaw->gyros[ATTITUDERAW_GYROS_X] += gyro_correct_int[0];
		attitudeRaw->gyros[ATTITUDERAW_GYROS_Y] += gyro_correct_int[1];
		attitudeRaw->gyros[ATTITUDERAW_GYROS_Z] += gyro_correct_int[2];
	}

	// Because most crafts wont get enough information from gravity to zero yaw gyro, we try
	// and make it average zero (weakly)
	gyro_correct_int[2] += - attitudeRaw->gyros[ATTITUDERAW_GYROS_Z] * yawBiasRate;
}
Example #7
0
/*
 * Although yaw correction is done in horizontal plane, it is 
 *  computed in 3 dimensions, just in case we change our minds later.
 */
void yaw_drift_MagGPS(float Rbe[3][3], bool gpsNewData_flag, bool magNewData_flag, float *errYaw_b)
{
#if defined (PIOS_INCLUDE_GPS) || defined (PIOS_INCLUDE_MAGNETOMETER)
	
	//      Form the horizontal direction over ground based on rmat
	float horizDirOverGndRmat[3];
	
	//Define forward vector in earth frame, Rbe' * [1;0;0], and eliminate vertical component from vector
	horizDirOverGndRmat[0] = Rbe[0][0];
	horizDirOverGndRmat[1] = Rbe[0][1];
	horizDirOverGndRmat[2] = 0;
	
#if defined (PIOS_INCLUDE_GPS)
	if (gpsNewData_flag) {
		
		GPSVelocityData gpsVelocity;
		GPSVelocityGet(&gpsVelocity);
		
		if (fabs(gpsVelocity.North) > GPS_SPEED_MIN
		    || fabs(gpsVelocity.East) > GPS_SPEED_MIN) {
			float errorGPSYaw_e;
			float errorGPSYaw_b[3];
			float normGPS =
			sqrtf(gpsVelocity.North * gpsVelocity.North +
					gpsVelocity.East * gpsVelocity.East);
			float horizDirOverGndGPS[3] = { gpsVelocity.North / normGPS, gpsVelocity.East / normGPS, 0 };	//Normalized vector
			
			// vector cross product to get the rotation error in ground frame. However, save several processor cycles by 
			// condensing the math to take advantage of the cross products null entries on the x and y elements.
			// errorGPSYaw_e = horizDirOverGndRmat X horizDirOverGndGPS
			errorGPSYaw_e =
			horizDirOverGndRmat[0] * horizDirOverGndGPS[1] -
			horizDirOverGndGPS[0] * horizDirOverGndRmat[1];
			
			// Rotate error to body frame. Again, take advantage of the yaw error vector [0;0;errorGPSYaw_e]'s null entries
			// errorGPSYaw_b = Rbe * errorGPSYaw_e;
			errorGPSYaw_b[0] = Rbe[0][2] * errorGPSYaw_e;
			errorGPSYaw_b[1] = Rbe[1][2] * errorGPSYaw_e;
			errorGPSYaw_b[2] = Rbe[2][2] * errorGPSYaw_e;
			
			//Sum error with existing error
			errYaw_b[0] += errorGPSYaw_b[0] * GPS_YAW_KP;
			errYaw_b[1] += errorGPSYaw_b[1] * GPS_YAW_KP;
			errYaw_b[2] += errorGPSYaw_b[2] * GPS_YAW_KP;
		}
	}
#endif
	
	// TODO: Create a flag to indicate whether mag data is present (or check for updates of MagnetometerData)
#if defined (PIOS_INCLUDE_MAGNETOMETER)
	if (magNewData_flag) {
		MagnetometerData magnetometerData;
		MagnetometerGet(&magnetometerData);
		
		float errorMagYaw_e;
		float errorMagYaw_b[3];
		float horizDirOverGndMag[3];
		float mags_b[3] = { magnetometerData.x, magnetometerData.y, magnetometerData.z };
		
		// Rotate magnetometer to earth frame and eliminate vertical component
		rot_mult(Rbe, mags_b, horizDirOverGndMag, true);
		horizDirOverGndMag[2] = 0;
		
		//Compute norm
		float normMag = VectorMagnitude(horizDirOverGndMag);
		
		//Normalize mag_vector. Recall that horizDirOverGndMag[2]=0
		horizDirOverGndMag[0] /= normMag;
		horizDirOverGndMag[1] /= normMag;
		
		// vector cross product to get the rotation error in ground frame. However, save several processor cycles by 
		// condensing the math to take advantage of the cross products null entries on the x and y elements.
		// errorMagYaw_e = horizDirOverGndRmat X horizDirOverGndMag
		errorMagYaw_e = horizDirOverGndRmat[0] * horizDirOverGndMag[1] -
		horizDirOverGndMag[0] * horizDirOverGndRmat[1];
		
		// Rotate error to body frame. Again, take advantage of the yaw error vector [0;0;errorGPSYaw_e]'s null entries
		// errorMagYaw_b = Rbe * errorMagYaw_e;
		errorMagYaw_b[0] = Rbe[0][2] * errorMagYaw_e;
		errorMagYaw_b[1] = Rbe[1][2] * errorMagYaw_e;
		errorMagYaw_b[2] = Rbe[2][2] * errorMagYaw_e;
		
		errYaw_b[0] += errorMagYaw_b[0] * MAG_YAW_KP;
		errYaw_b[1] += errorMagYaw_b[1] * MAG_YAW_KP;
		errYaw_b[2] += errorMagYaw_b[2] * MAG_YAW_KP;
	}
#endif
#endif
}
Example #8
0
/*
 * Correct sensor drift, using the DCM approach from W. Premerlani et. al
 */
void Premerlani_GPS(float *accels, float *gyros, float Rbe[3][3], const float delT, bool GPS_Drift_Compensation, GlobalAttitudeVariables *glblAtt, float *omegaCorrP)
{
	float errYaw_b[3] = { 0, 0, 0 };
	float errRollPitch_b[3] = { 0, 0, 0 };
	
	float normOmegaScalar = VectorMagnitude(gyros);
	
	//Correct roll-pitch drift via GPS and accelerometer
	//The math is derived from Roll-Pitch Gyro Drift Compensation, Rev.3, by W. Premerlani
#if defined (PIOS_INCLUDE_GPS)
	if (drft->gpsPresent_flag && GPS_Drift_Compensation) {
		float accels_e[3];
		
		//Rotate accelerometer readings into Earth frame. Note that we need to take the transpose of Rbe.
		rot_mult(Rbe, accels, accels_e, TRUE);
		
		//Integrate accelerometer measurements in Earth frame
		drft->accels_e_integrator[0] += accels_e[0] * delT;
		drft->accels_e_integrator[1] += accels_e[1] * delT;
		drft->accels_e_integrator[2] += accels_e[2] * delT;
		
		drft->delT_between_GPS += delT;
		
		//Check if the GPS has new information.
		if (!
		    (drft->
		     gpsVelocityDataConsumption_flag & GPS_CONSUMED_BY_RPY)) {
				 
				 //Compute drift correction, errRollPitch_b, from GPS
				 rollPitch_drift_GPS(Rbe, drft->accels_e_integrator,
											drft->delT_between_GPS,
											errRollPitch_b);
				 
				 //Reset integrator
				 memset(drft->accels_e_integrator, 0,
						  sizeof(drft->accels_e_integrator));
				 
				 //Mark GPS data as consumed by this function
				 drft->gpsVelocityDataConsumption_flag |=
			    GPS_CONSUMED_BY_RPY;
				 
				 drft->delT_between_GPS = 0;
				 
			 }
	}
#endif
	
	if (!GPS_Drift_Compensation) {
#if defined (PIOS_INCLUDE_GPS) && 0 || defined (PIOS_INCLUDE_MAGNETOMETER)
		if (!(drft->gpsVelocityDataConsumption_flag & GPS_CONSUMED_BY_Y)) {
			// We're actually using new GPS data here, but it's already been stored in old by the previous function
			yaw_drift_MagGPS(Rbe, true, drft->magNewData_flag, errYaw_b);	
			
			// Mark GPS data as consumed by this function
			drft->gpsVelocityDataConsumption_flag |= GPS_CONSUMED_BY_Y;
		} else {
			// In addition to calculating the roll-pitch-yaw error, we can calculate yaw drift, errYaw_b, based on GPS and attitude data
			// We're actually using new GPS data here, but it's already been stored in old by the previous function
			yaw_drift_MagGPS(Rbe, false, drft->magNewData_flag, errYaw_b);	
		}
		
		// Reset flag. Not the best place to do it, but it's messy anywhere else
		if (drft->magNewData_flag) {
			drft->magNewData_flag = false;
		}
#endif
		//In addition, we can calculate roll-pitch error with only the aid of an accelerometer
#if defined(PIOS_GPS_PROVIDES_AIRSPEED)
		AirspeedActualData airspeedActualData;
		AirspeedActualGet(&airspeedActualData);
		float airspeed_tas = airspeedActualData.TrueAirspeed;
#else
		float airspeed_tas = 0;
#endif
		rollPitch_drift_accel(accels, gyros, Rbe, airspeed_tas,
									 errRollPitch_b);
	}
	
	// Calculate gyro drift, based on all errors
	gyro_drift(gyros, errYaw_b, errRollPitch_b, normOmegaScalar, delT, omegaCorrP, drft->omegaCorrI);
	
	//Calculate final drift response
	gyros[0] += omegaCorrP[0] + drft->omegaCorrI[0];
	gyros[1] += omegaCorrP[1] + drft->omegaCorrI[1];
	gyros[2] += omegaCorrP[2] + drft->omegaCorrI[2];
	
	//Add 0.0001% of proportional error back into gyroscope bias offset. This keeps DC elements out of the raw gyroscope data.
	glblAtt->gyro_correct_int[0] += omegaCorrP[0] / 1000000.0f;
	glblAtt->gyro_correct_int[1] += omegaCorrP[1] / 1000000.0f;
	
	// Because most crafts wont get enough information from gravity to zero yaw gyro, we try
	// and make it average zero (weakly)
	glblAtt->gyro_correct_int[2] += -gyros[2] * glblAtt->yawBiasRate;
}
Example #9
0
static int32_t updateAttitudeComplementary(bool first_run)
{
	UAVObjEvent ev;
	GyrosData gyrosData;
	AccelsData accelsData;
	static int32_t timeval;
	float dT;
	static uint8_t init = 0;

	// Wait until the AttitudeRaw object is updated, if a timeout then go to failsafe
	if ( xQueueReceive(gyroQueue, &ev, FAILSAFE_TIMEOUT_MS / portTICK_RATE_MS) != pdTRUE ||
	     xQueueReceive(accelQueue, &ev, 1 / portTICK_RATE_MS) != pdTRUE )
	{
		// When one of these is updated so should the other
		// Do not set attitude timeout warnings in simulation mode
		if (!AttitudeActualReadOnly()){
			AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE,SYSTEMALARMS_ALARM_WARNING);
			return -1;
		}
	}

	AccelsGet(&accelsData);

	// During initialization and 
	FlightStatusData flightStatus;
	FlightStatusGet(&flightStatus);
	if(first_run) {
#if defined(PIOS_INCLUDE_HMC5883)
		// To initialize we need a valid mag reading
		if ( xQueueReceive(magQueue, &ev, 0 / portTICK_RATE_MS) != pdTRUE )
			return -1;
		MagnetometerData magData;
		MagnetometerGet(&magData);
#else
		MagnetometerData magData;
		magData.x = 100;
		magData.y = 0;
		magData.z = 0;
#endif
		AttitudeActualData attitudeActual;
		AttitudeActualGet(&attitudeActual);
		init = 0;
		attitudeActual.Roll = atan2f(-accelsData.y, -accelsData.z) * 180.0f / F_PI;
		attitudeActual.Pitch = atan2f(accelsData.x, -accelsData.z) * 180.0f / F_PI;
		attitudeActual.Yaw = atan2f(-magData.y, magData.x) * 180.0f / F_PI;

		RPY2Quaternion(&attitudeActual.Roll,&attitudeActual.q1);
		AttitudeActualSet(&attitudeActual);

		timeval = PIOS_DELAY_GetRaw();

		return 0;

	}

	if((init == 0 && xTaskGetTickCount() < 7000) && (xTaskGetTickCount() > 1000)) {
		// For first 7 seconds use accels to get gyro bias
		attitudeSettings.AccelKp = 1;
		attitudeSettings.AccelKi = 0.9;
		attitudeSettings.YawBiasRate = 0.23;
		magKp = 1;
	} else if ((attitudeSettings.ZeroDuringArming == ATTITUDESETTINGS_ZERODURINGARMING_TRUE) && (flightStatus.Armed == FLIGHTSTATUS_ARMED_ARMING)) {
		attitudeSettings.AccelKp = 1;
		attitudeSettings.AccelKi = 0.9;
		attitudeSettings.YawBiasRate = 0.23;
		magKp = 1;
		init = 0;
	} else if (init == 0) {
		// Reload settings (all the rates)
		AttitudeSettingsGet(&attitudeSettings);
		magKp = 0.01f;
		init = 1;
	}

	GyrosGet(&gyrosData);

	// Compute the dT using the cpu clock
	dT = PIOS_DELAY_DiffuS(timeval) / 1000000.0f;
	timeval = PIOS_DELAY_GetRaw();

	float q[4];

	AttitudeActualData attitudeActual;
	AttitudeActualGet(&attitudeActual);

	float grot[3];
	float accel_err[3];

	// Get the current attitude estimate
	quat_copy(&attitudeActual.q1, q);

	// Rotate gravity to body frame and cross with accels
	grot[0] = -(2 * (q[1] * q[3] - q[0] * q[2]));
	grot[1] = -(2 * (q[2] * q[3] + q[0] * q[1]));
	grot[2] = -(q[0] * q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3]);
	CrossProduct((const float *) &accelsData.x, (const float *) grot, accel_err);

	// Account for accel magnitude
	accel_mag = accelsData.x*accelsData.x + accelsData.y*accelsData.y + accelsData.z*accelsData.z;
	accel_mag = sqrtf(accel_mag);
	accel_err[0] /= accel_mag;
	accel_err[1] /= accel_mag;
	accel_err[2] /= accel_mag;	

	if ( xQueueReceive(magQueue, &ev, 0) != pdTRUE )
	{
		// Rotate gravity to body frame and cross with accels
		float brot[3];
		float Rbe[3][3];
		MagnetometerData mag;
		
		Quaternion2R(q, Rbe);
		MagnetometerGet(&mag);

		// If the mag is producing bad data don't use it (normally bad calibration)
		if  (mag.x == mag.x && mag.y == mag.y && mag.z == mag.z) {
			rot_mult(Rbe, homeLocation.Be, brot);

			float mag_len = sqrtf(mag.x * mag.x + mag.y * mag.y + mag.z * mag.z);
			mag.x /= mag_len;
			mag.y /= mag_len;
			mag.z /= mag_len;

			float bmag = sqrtf(brot[0] * brot[0] + brot[1] * brot[1] + brot[2] * brot[2]);
			brot[0] /= bmag;
			brot[1] /= bmag;
			brot[2] /= bmag;

			// Only compute if neither vector is null
			if (bmag < 1 || mag_len < 1)
				mag_err[0] = mag_err[1] = mag_err[2] = 0;
			else
				CrossProduct((const float *) &mag.x, (const float *) brot, mag_err);
		}
	} else {
		mag_err[0] = mag_err[1] = mag_err[2] = 0;
	}

	// Accumulate integral of error.  Scale here so that units are (deg/s) but Ki has units of s
	GyrosBiasData gyrosBias;
	GyrosBiasGet(&gyrosBias);
	gyrosBias.x -= accel_err[0] * attitudeSettings.AccelKi;
	gyrosBias.y -= accel_err[1] * attitudeSettings.AccelKi;
	gyrosBias.z -= mag_err[2] * magKi;
	GyrosBiasSet(&gyrosBias);

	// Correct rates based on error, integral component dealt with in updateSensors
	gyrosData.x += accel_err[0] * attitudeSettings.AccelKp / dT;
	gyrosData.y += accel_err[1] * attitudeSettings.AccelKp / dT;
	gyrosData.z += accel_err[2] * attitudeSettings.AccelKp / dT + mag_err[2] * magKp / dT;

	// Work out time derivative from INSAlgo writeup
	// Also accounts for the fact that gyros are in deg/s
	float qdot[4];
	qdot[0] = (-q[1] * gyrosData.x - q[2] * gyrosData.y - q[3] * gyrosData.z) * dT * F_PI / 180 / 2;
	qdot[1] = (q[0] * gyrosData.x - q[3] * gyrosData.y + q[2] * gyrosData.z) * dT * F_PI / 180 / 2;
	qdot[2] = (q[3] * gyrosData.x + q[0] * gyrosData.y - q[1] * gyrosData.z) * dT * F_PI / 180 / 2;
	qdot[3] = (-q[2] * gyrosData.x + q[1] * gyrosData.y + q[0] * gyrosData.z) * dT * F_PI / 180 / 2;

	// Take a time step
	q[0] = q[0] + qdot[0];
	q[1] = q[1] + qdot[1];
	q[2] = q[2] + qdot[2];
	q[3] = q[3] + qdot[3];

	if(q[0] < 0) {
		q[0] = -q[0];
		q[1] = -q[1];
		q[2] = -q[2];
		q[3] = -q[3];
	}

	// Renomalize
	qmag = sqrtf(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
	q[0] = q[0] / qmag;
	q[1] = q[1] / qmag;
	q[2] = q[2] / qmag;
	q[3] = q[3] / qmag;

	// If quaternion has become inappropriately short or is nan reinit.
	// THIS SHOULD NEVER ACTUALLY HAPPEN
	if((fabs(qmag) < 1.0e-3f) || (qmag != qmag)) {
		q[0] = 1;
		q[1] = 0;
		q[2] = 0;
		q[3] = 0;
	}

	quat_copy(q, &attitudeActual.q1);

	// Convert into eueler degrees (makes assumptions about RPY order)
	Quaternion2RPY(&attitudeActual.q1,&attitudeActual.Roll);

	AttitudeActualSet(&attitudeActual);

	// Flush these queues for avoid errors
	xQueueReceive(baroQueue, &ev, 0);
	if ( xQueueReceive(gpsQueue, &ev, 0) == pdTRUE && homeLocation.Set == HOMELOCATION_SET_TRUE ) {
		float NED[3];
		// Transform the GPS position into NED coordinates
		GPSPositionData gpsPosition;
		GPSPositionGet(&gpsPosition);
		getNED(&gpsPosition, NED);
		
		PositionActualData positionActual;
		PositionActualGet(&positionActual);
		positionActual.North = NED[0];
		positionActual.East = NED[1];
		positionActual.Down = NED[2];
		PositionActualSet(&positionActual);
	}

	if ( xQueueReceive(gpsVelQueue, &ev, 0) == pdTRUE ) {
		// Transform the GPS position into NED coordinates
		GPSVelocityData gpsVelocity;
		GPSVelocityGet(&gpsVelocity);

		VelocityActualData velocityActual;
		VelocityActualGet(&velocityActual);
		velocityActual.North = gpsVelocity.North;
		velocityActual.East = gpsVelocity.East;
		velocityActual.Down = gpsVelocity.Down;
		VelocityActualSet(&velocityActual);
	}


	AlarmsClear(SYSTEMALARMS_ALARM_ATTITUDE);

	return 0;
}
Example #10
0
static void settingsUpdatedCb(UAVObjEvent * objEv) {
    AttitudeSettingsData attitudeSettings;
    AttitudeSettingsGet(&attitudeSettings);
    SensorSettingsGet(&sensorSettings);


    accelKp = attitudeSettings.AccelKp;
    accelKi = attitudeSettings.AccelKi;
    yawBiasRate = attitudeSettings.YawBiasRate;

    // Calculate accel filter alpha, in the same way as for gyro data in stabilization module.
    const float fakeDt = 0.0025f;
    if(attitudeSettings.AccelTau < 0.0001f) {
        accel_alpha = 0;   // not trusting this to resolve to 0
        accel_filter_enabled = false;
    } else {
        accel_alpha = expf(-fakeDt  / attitudeSettings.AccelTau);
        accel_filter_enabled = true;
    }

    zero_during_arming = attitudeSettings.ZeroDuringArming == ATTITUDESETTINGS_ZERODURINGARMING_TRUE;
    bias_correct_gyro = attitudeSettings.BiasCorrectGyro == ATTITUDESETTINGS_BIASCORRECTGYRO_TRUE;

    gyro_correct_int[0] = 0;
    gyro_correct_int[1] = 0;
    gyro_correct_int[2] = 0;

    // Indicates not to expend cycles on rotation
    if(attitudeSettings.BoardRotation[0] == 0 && attitudeSettings.BoardRotation[1] == 0 &&
            attitudeSettings.BoardRotation[2] == 0) {
        rotate = 0;

        // Shouldn't be used but to be safe
        float rotationQuat[4] = {1,0,0,0};
        Quaternion2R(rotationQuat, Rsb);
    } else {
        float rotationQuat[4];
        const float rpy[3] = {attitudeSettings.BoardRotation[ATTITUDESETTINGS_BOARDROTATION_ROLL] / 100.0f,
                              attitudeSettings.BoardRotation[ATTITUDESETTINGS_BOARDROTATION_PITCH] / 100.0f,
                              attitudeSettings.BoardRotation[ATTITUDESETTINGS_BOARDROTATION_YAW] / 100.0f
                             };
        RPY2Quaternion(rpy, rotationQuat);
        Quaternion2R(rotationQuat, Rsb);
        rotate = 1;
    }

    if (attitudeSettings.TrimFlight == ATTITUDESETTINGS_TRIMFLIGHT_START) {
        trim_accels[0] = 0;
        trim_accels[1] = 0;
        trim_accels[2] = 0;
        trim_samples = 0;
        trim_requested = true;
    } else if (attitudeSettings.TrimFlight == ATTITUDESETTINGS_TRIMFLIGHT_LOAD) {
        trim_requested = false;

        // Get sensor data  mean
        float a_body[3] = { trim_accels[0] / trim_samples,
                            trim_accels[1] / trim_samples,
                            trim_accels[2] / trim_samples
                          };

        // Inverse rotation of sensor data, from body frame into sensor frame
        float a_sensor[3];
        rot_mult(Rsb, a_body, a_sensor, false);

        // Temporary variables
        float psi, theta, phi;

        psi = attitudeSettings.BoardRotation[ATTITUDESETTINGS_BOARDROTATION_YAW] * DEG2RAD / 100.0f;

        float cP = cosf(psi);
        float sP = sinf(psi);

        // In case psi is too small, we have to use a different equation to solve for theta
        if (fabsf(psi) > PI / 2)
            theta = atanf((a_sensor[1] + cP * (sP * a_sensor[0] -
                                               cP * a_sensor[1])) / (sP * a_sensor[2]));
        else
            theta = atanf((a_sensor[0] - sP * (sP * a_sensor[0] -
                                               cP * a_sensor[1])) / (cP * a_sensor[2]));

        phi = atan2f((sP * a_sensor[0] - cP * a_sensor[1]) / GRAVITY,
                     (a_sensor[2] / cosf(theta) / GRAVITY));

        attitudeSettings.BoardRotation[ATTITUDESETTINGS_BOARDROTATION_ROLL] = phi * RAD2DEG * 100.0f;
        attitudeSettings.BoardRotation[ATTITUDESETTINGS_BOARDROTATION_PITCH] = theta * RAD2DEG * 100.0f;

        attitudeSettings.TrimFlight = ATTITUDESETTINGS_TRIMFLIGHT_NORMAL;
        AttitudeSettingsSet(&attitudeSettings);

    }
}