mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2024-12-02 10:24:11 +01:00
Flight/AHRS Communications: Switch to Les' very nice UAVObject communication
scheme git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@1835 ebee16cc-31ac-478f-84a7-5cbb03baadba
This commit is contained in:
parent
62300c9682
commit
ea3fb03c7f
@ -82,7 +82,10 @@ STMUSBDIR = $(STMLIBDIR)/STM32_USB-FS-Device_Driver
|
|||||||
STMSPDSRCDIR = $(STMSPDDIR)/src
|
STMSPDSRCDIR = $(STMSPDDIR)/src
|
||||||
STMSPDINCDIR = $(STMSPDDIR)/inc
|
STMSPDINCDIR = $(STMSPDDIR)/inc
|
||||||
CMSISDIR = $(STMLIBDIR)/CMSIS/Core/CM3
|
CMSISDIR = $(STMLIBDIR)/CMSIS/Core/CM3
|
||||||
|
OPDIR = ../OpenPilot
|
||||||
|
OPUAVOBJ = $(OPDIR)/UAVObjects
|
||||||
|
OPUAVOBJINC = $(OPUAVOBJ)/inc
|
||||||
|
OPSYSINC = $(OPDIR)/System/inc
|
||||||
|
|
||||||
# List C source files here. (C dependencies are automatically generated.)
|
# List C source files here. (C dependencies are automatically generated.)
|
||||||
# use file-extension c for "c-only"-files
|
# use file-extension c for "c-only"-files
|
||||||
@ -91,8 +94,10 @@ CMSISDIR = $(STMLIBDIR)/CMSIS/Core/CM3
|
|||||||
SRC = ahrs.c
|
SRC = ahrs.c
|
||||||
SRC += pios_board.c
|
SRC += pios_board.c
|
||||||
SRC += ahrs_adc.c
|
SRC += ahrs_adc.c
|
||||||
SRC += ahrs_fsm.c
|
|
||||||
SRC += ahrs_timer.c
|
SRC += ahrs_timer.c
|
||||||
|
SRC += $(FLIGHTLIB)/ahrs_spi_comm.c
|
||||||
|
SRC += $(FLIGHTLIB)/ahrs_comm_objects.c
|
||||||
|
SRC += $(FLIGHTLIB)/ahrs_spi_program_slave.c
|
||||||
SRC += insgps.c
|
SRC += insgps.c
|
||||||
SRC += $(FLIGHTLIB)/CoordinateConversions.c
|
SRC += $(FLIGHTLIB)/CoordinateConversions.c
|
||||||
|
|
||||||
@ -110,7 +115,6 @@ SRC += $(PIOSSTM32F10X)/pios_exti.c
|
|||||||
## PIOS Hardware (Common)
|
## PIOS Hardware (Common)
|
||||||
SRC += $(PIOSCOMMON)/pios_com.c
|
SRC += $(PIOSCOMMON)/pios_com.c
|
||||||
SRC += $(PIOSCOMMON)/pios_hmc5843.c
|
SRC += $(PIOSCOMMON)/pios_hmc5843.c
|
||||||
SRC += $(PIOSCOMMON)/pios_opahrs_proto.c
|
|
||||||
SRC += $(PIOSCOMMON)/printf-stdarg.c
|
SRC += $(PIOSCOMMON)/printf-stdarg.c
|
||||||
|
|
||||||
## CMSIS for STM32
|
## CMSIS for STM32
|
||||||
@ -172,6 +176,7 @@ EXTRAINCDIRS += $(PIOSBOARDS)
|
|||||||
EXTRAINCDIRS += $(STMSPDINCDIR)
|
EXTRAINCDIRS += $(STMSPDINCDIR)
|
||||||
EXTRAINCDIRS += $(CMSISDIR)
|
EXTRAINCDIRS += $(CMSISDIR)
|
||||||
EXTRAINCDIRS += $(AHRSINC)
|
EXTRAINCDIRS += $(AHRSINC)
|
||||||
|
EXTRAINCDIRS += $(OPUAVOBJINC)
|
||||||
|
|
||||||
# List any extra directories to look for library files here.
|
# List any extra directories to look for library files here.
|
||||||
# Also add directories where the linker should search for
|
# Also add directories where the linker should search for
|
||||||
@ -216,6 +221,7 @@ DEBUGF = dwarf-2
|
|||||||
CDEFS = -DSTM32F10X_$(MODEL)
|
CDEFS = -DSTM32F10X_$(MODEL)
|
||||||
CDEFS += -DUSE_STDPERIPH_DRIVER
|
CDEFS += -DUSE_STDPERIPH_DRIVER
|
||||||
CDEFS += -DUSE_$(BOARD)
|
CDEFS += -DUSE_$(BOARD)
|
||||||
|
CDEFS += -DIN_AHRS
|
||||||
ifeq ($(USE_BOOTLOADER), YES)
|
ifeq ($(USE_BOOTLOADER), YES)
|
||||||
CDEFS += -DUSE_BOOTLOADER
|
CDEFS += -DUSE_BOOTLOADER
|
||||||
endif
|
endif
|
||||||
|
@ -36,9 +36,10 @@
|
|||||||
#include "ahrs_adc.h"
|
#include "ahrs_adc.h"
|
||||||
#include "ahrs_timer.h"
|
#include "ahrs_timer.h"
|
||||||
#include "pios_opahrs_proto.h"
|
#include "pios_opahrs_proto.h"
|
||||||
#include "ahrs_fsm.h" /* lfsm_state */
|
//#include "ahrs_fsm.h" /* lfsm_state */
|
||||||
#include "insgps.h"
|
#include "insgps.h"
|
||||||
#include "CoordinateConversions.h"
|
#include "CoordinateConversions.h"
|
||||||
|
#include "ahrs_spi_comm.h"
|
||||||
|
|
||||||
// For debugging the raw sensors
|
// For debugging the raw sensors
|
||||||
//#define DUMP_RAW
|
//#define DUMP_RAW
|
||||||
@ -156,6 +157,11 @@ void process_spi_request(void);
|
|||||||
void downsample_data(void);
|
void downsample_data(void);
|
||||||
void calibrate_sensors(void);
|
void calibrate_sensors(void);
|
||||||
void reset_values();
|
void reset_values();
|
||||||
|
void send_calibration(void);
|
||||||
|
void altitude_callback(AhrsObjHandle obj);
|
||||||
|
void calibration_callback(AhrsObjHandle obj);
|
||||||
|
void gps_callback(AhrsObjHandle obj);
|
||||||
|
void settings_callback(AhrsObjHandle obj);
|
||||||
|
|
||||||
volatile uint32_t last_counter_idle_start = 0;
|
volatile uint32_t last_counter_idle_start = 0;
|
||||||
volatile uint32_t last_counter_idle_end = 0;
|
volatile uint32_t last_counter_idle_end = 0;
|
||||||
@ -171,14 +177,10 @@ uint32_t counter_val;
|
|||||||
//! Filter coefficients used in decimation. Limited order so filter can't run between samples
|
//! Filter coefficients used in decimation. Limited order so filter can't run between samples
|
||||||
int16_t fir_coeffs[50];
|
int16_t fir_coeffs[50];
|
||||||
|
|
||||||
//! Indicates the communications are requesting a calibration
|
|
||||||
uint8_t calibration_pending = FALSE;
|
|
||||||
|
|
||||||
//! The oversampling rate, ekf is 2k / this
|
//! The oversampling rate, ekf is 2k / this
|
||||||
static uint8_t adc_oversampling = 25;
|
static uint8_t adc_oversampling = 17;
|
||||||
|
|
||||||
//! Flag for OP to check if AHRS has been initialized yet
|
|
||||||
enum initialized_mode initialized = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
@ -214,19 +216,38 @@ int main()
|
|||||||
/* Magnetic sensor system */
|
/* Magnetic sensor system */
|
||||||
PIOS_I2C_Init();
|
PIOS_I2C_Init();
|
||||||
PIOS_HMC5843_Init();
|
PIOS_HMC5843_Init();
|
||||||
|
|
||||||
// Get 3 ID bytes
|
// Get 3 ID bytes
|
||||||
strcpy((char *)mag_data.id, "ZZZ");
|
strcpy((char *)mag_data.id, "ZZZ");
|
||||||
PIOS_HMC5843_ReadID(mag_data.id);
|
PIOS_HMC5843_ReadID(mag_data.id);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* SPI link to master */
|
/* SPI link to master */
|
||||||
PIOS_SPI_Init();
|
// PIOS_SPI_Init();
|
||||||
|
|
||||||
lfsm_init();
|
// lfsm_init();
|
||||||
reset_values();
|
reset_values();
|
||||||
|
|
||||||
ahrs_state = AHRS_IDLE;
|
ahrs_state = AHRS_IDLE;
|
||||||
|
AhrsInitComms();
|
||||||
|
ahrs_state = AHRS_IDLE;
|
||||||
|
while(!AhrsLinkReady()) {
|
||||||
|
AhrsPoll();
|
||||||
|
while(ahrs_state != AHRS_DATA_READY) ;
|
||||||
|
ahrs_state = AHRS_PROCESSING;
|
||||||
|
downsample_data();
|
||||||
|
ahrs_state = AHRS_IDLE;
|
||||||
|
if((total_conversion_blocks % 10) == 0)
|
||||||
|
PIOS_LED_Toggle(LED1);
|
||||||
|
}
|
||||||
|
/* we didn't connect the callbacks before because we have to wait
|
||||||
|
for all data to be up to date before doing anything*/
|
||||||
|
AHRSCalibrationConnectCallback(calibration_callback);
|
||||||
|
GPSPositionConnectCallback(gps_callback);
|
||||||
|
BaroAltitudeConnectCallback(altitude_callback);
|
||||||
|
AHRSSettingsConnectCallback(settings_callback);
|
||||||
|
|
||||||
|
calibration_callback(AHRSCalibrationHandle()); //force an update
|
||||||
|
|
||||||
|
|
||||||
/* Use simple averaging filter for now */
|
/* Use simple averaging filter for now */
|
||||||
for (int i = 0; i < adc_oversampling; i++)
|
for (int i = 0; i < adc_oversampling; i++)
|
||||||
@ -235,12 +256,10 @@ int main()
|
|||||||
|
|
||||||
INSGPSInit();
|
INSGPSInit();
|
||||||
|
|
||||||
while(initialized != AHRS_INITIALIZED)
|
|
||||||
process_spi_request();
|
|
||||||
|
|
||||||
#ifdef DUMP_RAW
|
#ifdef DUMP_RAW
|
||||||
int previous_conversion;
|
int previous_conversion;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
AhrsPoll();
|
||||||
int result;
|
int result;
|
||||||
uint8_t framing[16] =
|
uint8_t framing[16] =
|
||||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||||
@ -277,16 +296,21 @@ int main()
|
|||||||
timer_start();
|
timer_start();
|
||||||
|
|
||||||
/******************* Main EKF loop ****************************/
|
/******************* Main EKF loop ****************************/
|
||||||
while (1) {
|
while(1) {
|
||||||
|
AhrsPoll();
|
||||||
|
AhrsStatusData status;
|
||||||
|
AhrsStatusGet(&status);
|
||||||
|
status.CPULoad = ((float)running_counts /
|
||||||
|
(float)(idle_counts + running_counts)) * 100;
|
||||||
|
status.IdleTimePerCyle = idle_counts / (TIMER_RATE / 10000);
|
||||||
|
status.RunningTimePerCyle = running_counts / (TIMER_RATE / 10000);
|
||||||
|
status.DroppedUpdates = ekf_too_slow;
|
||||||
|
AhrsStatusSet(&status);
|
||||||
|
|
||||||
// Alive signal
|
// Alive signal
|
||||||
if ((total_conversion_blocks % 100) == 0)
|
if ((total_conversion_blocks % 100) == 0)
|
||||||
PIOS_LED_Toggle(LED1);
|
PIOS_LED_Toggle(LED1);
|
||||||
|
|
||||||
if (calibration_pending) {
|
|
||||||
calibrate_sensors();
|
|
||||||
calibration_pending = FALSE;
|
|
||||||
}
|
|
||||||
#if defined(PIOS_INCLUDE_HMC5843) && defined(PIOS_INCLUDE_I2C)
|
#if defined(PIOS_INCLUDE_HMC5843) && defined(PIOS_INCLUDE_I2C)
|
||||||
// Get magnetic readings
|
// Get magnetic readings
|
||||||
if (PIOS_HMC5843_NewDataAvailable()) {
|
if (PIOS_HMC5843_NewDataAvailable()) {
|
||||||
@ -296,6 +320,7 @@ int main()
|
|||||||
mag_data.scaled.axis[2] = (mag_data.raw.axis[2] * mag_data.calibration.scale[2]) + mag_data.calibration.bias[2];
|
mag_data.scaled.axis[2] = (mag_data.raw.axis[2] * mag_data.calibration.scale[2]) + mag_data.calibration.bias[2];
|
||||||
mag_data.updated = 1;
|
mag_data.updated = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
// Delay for valid data
|
// Delay for valid data
|
||||||
|
|
||||||
@ -543,6 +568,30 @@ void downsample_data()
|
|||||||
gyro_data.filtered.z += valid_data_buffer[5 + i * PIOS_ADC_NUM_PINS] * fir_coeffs[i];
|
gyro_data.filtered.z += valid_data_buffer[5 + i * PIOS_ADC_NUM_PINS] * fir_coeffs[i];
|
||||||
gyro_data.filtered.z /= fir_coeffs[adc_oversampling];
|
gyro_data.filtered.z /= fir_coeffs[adc_oversampling];
|
||||||
gyro_data.filtered.z = (gyro_data.filtered.z * gyro_data.calibration.scale[2]) + gyro_data.calibration.bias[2];
|
gyro_data.filtered.z = (gyro_data.filtered.z * gyro_data.calibration.scale[2]) + gyro_data.calibration.bias[2];
|
||||||
|
|
||||||
|
AttitudeRawData raw;
|
||||||
|
|
||||||
|
raw.gyros[0] = valid_data_buffer[1];
|
||||||
|
raw.gyros[1] = valid_data_buffer[3];
|
||||||
|
raw.gyros[2] = valid_data_buffer[5];
|
||||||
|
|
||||||
|
raw.gyros_filtered[0] = gyro_data.filtered.x;
|
||||||
|
raw.gyros_filtered[1] = gyro_data.filtered.y;
|
||||||
|
raw.gyros_filtered[2] = gyro_data.filtered.z;
|
||||||
|
|
||||||
|
raw.accels[0] = valid_data_buffer[2];
|
||||||
|
raw.accels[1] = valid_data_buffer[0];
|
||||||
|
raw.accels[2] = valid_data_buffer[4];
|
||||||
|
|
||||||
|
raw.accels_filtered[0] = accel_data.filtered.x;
|
||||||
|
raw.accels_filtered[1] = accel_data.filtered.y;
|
||||||
|
raw.accels_filtered[2] = accel_data.filtered.z;
|
||||||
|
|
||||||
|
raw.magnetometers[0] = mag_data.scaled.axis[0];
|
||||||
|
raw.magnetometers[1] = mag_data.scaled.axis[1];
|
||||||
|
raw.magnetometers[2] = mag_data.scaled.axis[2];
|
||||||
|
|
||||||
|
AttitudeRawSet(&raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -565,6 +614,7 @@ void calibrate_sensors()
|
|||||||
float gyro_bias[3] = {0, 0, 0};
|
float gyro_bias[3] = {0, 0, 0};
|
||||||
float mag_bias[3] = {0, 0, 0};
|
float mag_bias[3] = {0, 0, 0};
|
||||||
|
|
||||||
|
|
||||||
for (i = 0, j = 0; i < NBIAS; i++) {
|
for (i = 0, j = 0; i < NBIAS; i++) {
|
||||||
while (ahrs_state != AHRS_DATA_READY) ;
|
while (ahrs_state != AHRS_DATA_READY) ;
|
||||||
ahrs_state = AHRS_PROCESSING;
|
ahrs_state = AHRS_PROCESSING;
|
||||||
@ -589,7 +639,7 @@ void calibrate_sensors()
|
|||||||
mag_bias[2] += mag_data.scaled.axis[2];
|
mag_bias[2] += mag_data.scaled.axis[2];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
process_spi_request();
|
|
||||||
}
|
}
|
||||||
mag_bias[0] /= j;
|
mag_bias[0] /= j;
|
||||||
mag_bias[1] /= j;
|
mag_bias[1] /= j;
|
||||||
@ -628,12 +678,16 @@ void calibrate_sensors()
|
|||||||
mag_data.calibration.variance[2] += pow(mag_data.scaled.axis[2]-mag_bias[2],2);
|
mag_data.calibration.variance[2] += pow(mag_data.scaled.axis[2]-mag_bias[2],2);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
process_spi_request();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mag_data.calibration.variance[0] /= j;
|
mag_data.calibration.variance[0] /= j;
|
||||||
mag_data.calibration.variance[1] /= j;
|
mag_data.calibration.variance[1] /= j;
|
||||||
mag_data.calibration.variance[2] /= j;
|
mag_data.calibration.variance[2] /= j;
|
||||||
|
|
||||||
|
gyro_data.calibration.bias[0] -= gyro_bias[0];
|
||||||
|
gyro_data.calibration.bias[1] -= gyro_bias[1];
|
||||||
|
gyro_data.calibration.bias[2] -= gyro_bias[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -669,259 +723,131 @@ void reset_values() {
|
|||||||
mag_data.calibration.variance[2] = 1;
|
mag_data.calibration.variance[2] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @addtogroup AHRS_SPI SPI Messaging
|
|
||||||
* @{
|
|
||||||
* @brief SPI protocol handling requests for data from OP mainboard
|
|
||||||
*/
|
|
||||||
|
|
||||||
static struct opahrs_msg_v1 link_tx_v1;
|
|
||||||
static struct opahrs_msg_v1 link_rx_v1;
|
|
||||||
static struct opahrs_msg_v1 user_rx_v1;
|
|
||||||
static struct opahrs_msg_v1 user_tx_v1;
|
|
||||||
|
|
||||||
void process_spi_request(void)
|
void process_spi_request(void)
|
||||||
{
|
{
|
||||||
bool msg_to_process = FALSE;
|
AttitudeActualData attitude;
|
||||||
|
attitude.q1 = attitude_data.quaternion.q1;
|
||||||
|
attitude.q2 = attitude_data.quaternion.q2;
|
||||||
|
attitude.q3 = attitude_data.quaternion.q3;
|
||||||
|
attitude.q4 = attitude_data.quaternion.q4;
|
||||||
|
float rpy[3];
|
||||||
|
Quaternion2RPY(&attitude_data.quaternion.q1, rpy);
|
||||||
|
attitude.Roll = rpy[0];
|
||||||
|
attitude.Pitch = rpy[1];
|
||||||
|
attitude.Yaw = rpy[2];
|
||||||
|
AttitudeActualSet(&attitude);
|
||||||
|
}
|
||||||
|
|
||||||
PIOS_IRQ_Disable();
|
void send_calibration(void)
|
||||||
/* Figure out if we're in an interesting stable state */
|
{
|
||||||
switch (lfsm_get_state()) {
|
AHRSCalibrationData cal;
|
||||||
case LFSM_STATE_USER_BUSY:
|
AHRSCalibrationGet(&cal);
|
||||||
msg_to_process = TRUE;
|
for(int ct=0; ct<3; ct++)
|
||||||
break;
|
{
|
||||||
case LFSM_STATE_INACTIVE:
|
cal.accel_var[ct] = accel_data.calibration.variance[ct];
|
||||||
/* Queue up a receive buffer */
|
cal.gyro_bias[ct] = gyro_data.calibration.bias[ct];
|
||||||
lfsm_user_set_rx_v1(&user_rx_v1);
|
cal.gyro_var[ct] = gyro_data.calibration.variance[ct];
|
||||||
lfsm_user_done();
|
cal.mag_var[ct] = mag_data.calibration.variance[ct];
|
||||||
break;
|
|
||||||
case LFSM_STATE_STOPPED:
|
|
||||||
/* Get things going */
|
|
||||||
lfsm_set_link_proto_v1(&link_tx_v1, &link_rx_v1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* Not a stable state */
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
PIOS_IRQ_Enable();
|
cal.measure_var = AHRSCALIBRATION_MEASURE_VAR_SET;
|
||||||
|
AHRSCalibrationSet(&cal);
|
||||||
|
}
|
||||||
|
|
||||||
if (!msg_to_process) {
|
/**
|
||||||
/* Nothing to do */
|
* @brief AHRS calibration callback
|
||||||
|
*
|
||||||
|
* Called when the OP board sets the calibration
|
||||||
|
*/
|
||||||
|
void calibration_callback(AhrsObjHandle obj)
|
||||||
|
{
|
||||||
|
AHRSCalibrationData cal;
|
||||||
|
AHRSCalibrationGet(&cal);
|
||||||
|
if(cal.measure_var == AHRSCALIBRATION_MEASURE_VAR_SET){
|
||||||
|
for(int ct=0; ct<3; ct++)
|
||||||
|
{
|
||||||
|
accel_data.calibration.scale[ct] = cal.accel_scale[ct];
|
||||||
|
accel_data.calibration.bias[ct] = cal.accel_bias[ct];
|
||||||
|
accel_data.calibration.variance[ct] = cal.accel_var[ct];
|
||||||
|
gyro_data.calibration.scale[ct] = cal.gyro_scale[ct];
|
||||||
|
gyro_data.calibration.bias[ct] = cal.gyro_bias[ct];
|
||||||
|
gyro_data.calibration.variance[ct] = cal.gyro_var[ct];
|
||||||
|
mag_data.calibration.bias[ct] = cal.mag_bias[ct];
|
||||||
|
mag_data.calibration.scale[ct] = cal.mag_scale[ct];
|
||||||
|
mag_data.calibration.variance[ct] = cal.mag_var[ct];
|
||||||
|
}
|
||||||
|
}else if(cal.measure_var == AHRSCALIBRATION_MEASURE_VAR_MEASURE){
|
||||||
|
calibrate_sensors();
|
||||||
|
AHRSCalibrationData cal;
|
||||||
|
AHRSCalibrationGet(&cal);
|
||||||
|
cal.measure_var = AHRSCALIBRATION_MEASURE_VAR_SET;
|
||||||
|
AHRSCalibrationSet(&cal);
|
||||||
|
|
||||||
|
}else if(cal.measure_var == AHRSCALIBRATION_MEASURE_VAR_ECHO){
|
||||||
|
send_calibration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gps_callback(AhrsObjHandle obj)
|
||||||
|
{
|
||||||
|
GPSPositionData pos;
|
||||||
|
GPSPositionGet(&pos);
|
||||||
|
HomeLocationData home;
|
||||||
|
HomeLocationGet(&home);
|
||||||
|
|
||||||
|
if(home.Set == HOMELOCATION_SET_FALSE || home.Indoor == HOMELOCATION_INDOOR_TRUE) {
|
||||||
|
gps_data.NED[0] = 0;
|
||||||
|
gps_data.NED[1] = 0;
|
||||||
|
gps_data.NED[2] = 0;
|
||||||
|
gps_data.groundspeed = 0;
|
||||||
|
gps_data.heading = 0;
|
||||||
|
gps_data.quality = -1; // indicates indoor mode, high variance zeros update
|
||||||
|
gps_data.updated = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (user_rx_v1.payload.user.t) {
|
if(pos.Status != GPSPOSITION_STATUS_FIX3D) //FIXME: Will this work? the old ahrs_comms does it differently.
|
||||||
case OPAHRS_MSG_V1_REQ_RESET:
|
{
|
||||||
PIOS_DELAY_WaitmS(user_rx_v1.payload.user.v.req.reset.
|
gps_data.quality = 0;
|
||||||
reset_delay_in_ms);
|
|
||||||
PIOS_SYS_Reset();
|
|
||||||
break;
|
|
||||||
case OPAHRS_MSG_V1_REQ_SERIAL:
|
|
||||||
opahrs_msg_v1_init_user_tx(&user_tx_v1,OPAHRS_MSG_V1_RSP_SERIAL);
|
|
||||||
PIOS_SYS_SerialNumberGet((char *) &(user_tx_v1.payload.user.v.rsp.
|
|
||||||
serial.serial_bcd));
|
|
||||||
lfsm_user_set_tx_v1(&user_tx_v1);
|
|
||||||
break;
|
|
||||||
case OPAHRS_MSG_V1_REQ_ALGORITHM:
|
|
||||||
opahrs_msg_v1_init_user_tx(&user_tx_v1,OPAHRS_MSG_V1_RSP_ALGORITHM);
|
|
||||||
ahrs_algorithm = user_rx_v1.payload.user.v.req.algorithm.algorithm;
|
|
||||||
lfsm_user_set_tx_v1(&user_tx_v1);
|
|
||||||
break;
|
|
||||||
case OPAHRS_MSG_V1_REQ_NORTH:
|
|
||||||
opahrs_msg_v1_init_user_tx(&user_tx_v1,OPAHRS_MSG_V1_RSP_NORTH);
|
|
||||||
INSSetMagNorth(user_rx_v1.payload.user.v.req.north.Be);
|
|
||||||
lfsm_user_set_tx_v1(&user_tx_v1);
|
|
||||||
break;
|
|
||||||
case OPAHRS_MSG_V1_REQ_CALIBRATION:
|
|
||||||
if (user_rx_v1.payload.user.v.req.calibration.
|
|
||||||
measure_var == AHRS_MEASURE) {
|
|
||||||
calibration_pending = TRUE;
|
|
||||||
} else if (user_rx_v1.payload.user.v.req.calibration.measure_var == AHRS_SET) {
|
|
||||||
|
|
||||||
// Set the accel calibration
|
|
||||||
accel_data.calibration.variance[0] = user_rx_v1.payload.user.v.req.calibration.accel_var[0];
|
|
||||||
accel_data.calibration.variance[1] = user_rx_v1.payload.user.v.req.calibration.accel_var[1];
|
|
||||||
accel_data.calibration.variance[2] = user_rx_v1.payload.user.v.req.calibration.accel_var[2];
|
|
||||||
accel_data.calibration.scale[0] = user_rx_v1.payload.user.v.req.calibration.accel_scale[0];
|
|
||||||
accel_data.calibration.scale[1] = user_rx_v1.payload.user.v.req.calibration.accel_scale[1];
|
|
||||||
accel_data.calibration.scale[2] = user_rx_v1.payload.user.v.req.calibration.accel_scale[2];
|
|
||||||
accel_data.calibration.bias[0] = user_rx_v1.payload.user.v.req.calibration.accel_bias[0];
|
|
||||||
accel_data.calibration.bias[1] = user_rx_v1.payload.user.v.req.calibration.accel_bias[1];
|
|
||||||
accel_data.calibration.bias[2] = user_rx_v1.payload.user.v.req.calibration.accel_bias[2];
|
|
||||||
|
|
||||||
// Set the gyro calibration
|
|
||||||
gyro_data.calibration.variance[0] = user_rx_v1.payload.user.v.req.calibration.gyro_var[0];
|
|
||||||
gyro_data.calibration.variance[1] = user_rx_v1.payload.user.v.req.calibration.gyro_var[1];
|
|
||||||
gyro_data.calibration.variance[2] = user_rx_v1.payload.user.v.req.calibration.gyro_var[2];
|
|
||||||
gyro_data.calibration.scale[0] = user_rx_v1.payload.user.v.req.calibration.gyro_scale[0];
|
|
||||||
gyro_data.calibration.scale[1] = user_rx_v1.payload.user.v.req.calibration.gyro_scale[1];
|
|
||||||
gyro_data.calibration.scale[2] = user_rx_v1.payload.user.v.req.calibration.gyro_scale[2];
|
|
||||||
gyro_data.calibration.bias[0] = user_rx_v1.payload.user.v.req.calibration.gyro_bias[0];
|
|
||||||
gyro_data.calibration.bias[1] = user_rx_v1.payload.user.v.req.calibration.gyro_bias[1];
|
|
||||||
gyro_data.calibration.bias[2] = user_rx_v1.payload.user.v.req.calibration.gyro_bias[2];
|
|
||||||
|
|
||||||
// Set the mag calibration
|
|
||||||
mag_data.calibration.variance[0] = user_rx_v1.payload.user.v.req.calibration.mag_var[0];
|
|
||||||
mag_data.calibration.variance[1] = user_rx_v1.payload.user.v.req.calibration.mag_var[1];
|
|
||||||
mag_data.calibration.variance[2] = user_rx_v1.payload.user.v.req.calibration.mag_var[2];
|
|
||||||
mag_data.calibration.scale[0] = user_rx_v1.payload.user.v.req.calibration.mag_scale[0];
|
|
||||||
mag_data.calibration.scale[1] = user_rx_v1.payload.user.v.req.calibration.mag_scale[1];
|
|
||||||
mag_data.calibration.scale[2] = user_rx_v1.payload.user.v.req.calibration.mag_scale[2];
|
|
||||||
mag_data.calibration.bias[0] = user_rx_v1.payload.user.v.req.calibration.mag_bias[0];
|
|
||||||
mag_data.calibration.bias[1] = user_rx_v1.payload.user.v.req.calibration.mag_bias[1];
|
|
||||||
mag_data.calibration.bias[2] = user_rx_v1.payload.user.v.req.calibration.mag_bias[2];
|
|
||||||
|
|
||||||
float zeros[3] = { 0, 0, 0 };
|
|
||||||
INSSetGyroBias(zeros); //gyro bias corrects in preprocessing
|
|
||||||
INSSetAccelVar(accel_data.calibration.variance);
|
|
||||||
INSSetGyroVar(gyro_data.calibration.variance);
|
|
||||||
float mag_var[3] = {mag_data.calibration.variance[1], mag_data.calibration.variance[0], mag_data.calibration.variance[2]};
|
|
||||||
INSSetMagVar(mag_var);
|
|
||||||
}
|
|
||||||
|
|
||||||
// echo back the values used
|
|
||||||
opahrs_msg_v1_init_user_tx(&user_tx_v1,
|
|
||||||
OPAHRS_MSG_V1_RSP_CALIBRATION);
|
|
||||||
user_tx_v1.payload.user.v.rsp.calibration.accel_var[0] = accel_data.calibration.variance[0];
|
|
||||||
user_tx_v1.payload.user.v.rsp.calibration.accel_var[1] = accel_data.calibration.variance[1];
|
|
||||||
user_tx_v1.payload.user.v.rsp.calibration.accel_var[2] = accel_data.calibration.variance[2];
|
|
||||||
user_tx_v1.payload.user.v.rsp.calibration.gyro_var[0] = gyro_data.calibration.variance[0];
|
|
||||||
user_tx_v1.payload.user.v.rsp.calibration.gyro_var[1] = gyro_data.calibration.variance[1];
|
|
||||||
user_tx_v1.payload.user.v.rsp.calibration.gyro_var[2] = gyro_data.calibration.variance[2];
|
|
||||||
user_tx_v1.payload.user.v.rsp.calibration.mag_var[0] = mag_data.calibration.variance[0];
|
|
||||||
user_tx_v1.payload.user.v.rsp.calibration.mag_var[1] = mag_data.calibration.variance[1];
|
|
||||||
user_tx_v1.payload.user.v.rsp.calibration.mag_var[2] = mag_data.calibration.variance[2];
|
|
||||||
|
|
||||||
lfsm_user_set_tx_v1(&user_tx_v1);
|
|
||||||
break;
|
|
||||||
case OPAHRS_MSG_V1_REQ_ATTITUDERAW:
|
|
||||||
opahrs_msg_v1_init_user_tx(&user_tx_v1,
|
|
||||||
OPAHRS_MSG_V1_RSP_ATTITUDERAW);
|
|
||||||
|
|
||||||
// Grab one sample from buffer to populate this
|
|
||||||
accel_data.raw.x = valid_data_buffer[0];
|
|
||||||
accel_data.raw.y = valid_data_buffer[2];
|
|
||||||
accel_data.raw.z = valid_data_buffer[4];
|
|
||||||
|
|
||||||
gyro_data.raw.x = valid_data_buffer[1];
|
|
||||||
gyro_data.raw.y = valid_data_buffer[3];
|
|
||||||
gyro_data.raw.z = valid_data_buffer[5];
|
|
||||||
|
|
||||||
gyro_data.temp.xy = valid_data_buffer[6];
|
|
||||||
gyro_data.temp.z = valid_data_buffer[7];
|
|
||||||
|
|
||||||
user_tx_v1.payload.user.v.rsp.attituderaw.mags.x =
|
|
||||||
mag_data.raw.axis[0];
|
|
||||||
user_tx_v1.payload.user.v.rsp.attituderaw.mags.y =
|
|
||||||
mag_data.raw.axis[1];
|
|
||||||
user_tx_v1.payload.user.v.rsp.attituderaw.mags.z =
|
|
||||||
mag_data.raw.axis[2];
|
|
||||||
|
|
||||||
user_tx_v1.payload.user.v.rsp.attituderaw.gyros.x =
|
|
||||||
gyro_data.raw.x;
|
|
||||||
user_tx_v1.payload.user.v.rsp.attituderaw.gyros.y =
|
|
||||||
gyro_data.raw.y;
|
|
||||||
user_tx_v1.payload.user.v.rsp.attituderaw.gyros.z =
|
|
||||||
gyro_data.raw.z;
|
|
||||||
|
|
||||||
user_tx_v1.payload.user.v.rsp.attituderaw.gyros_filtered.
|
|
||||||
x = gyro_data.filtered.x;
|
|
||||||
user_tx_v1.payload.user.v.rsp.attituderaw.gyros_filtered.
|
|
||||||
y = gyro_data.filtered.y;
|
|
||||||
user_tx_v1.payload.user.v.rsp.attituderaw.gyros_filtered.
|
|
||||||
z = gyro_data.filtered.z;
|
|
||||||
|
|
||||||
user_tx_v1.payload.user.v.rsp.attituderaw.gyros.xy_temp =
|
|
||||||
gyro_data.temp.xy;
|
|
||||||
user_tx_v1.payload.user.v.rsp.attituderaw.gyros.z_temp =
|
|
||||||
gyro_data.temp.z;
|
|
||||||
|
|
||||||
user_tx_v1.payload.user.v.rsp.attituderaw.accels.x =
|
|
||||||
accel_data.raw.x;
|
|
||||||
user_tx_v1.payload.user.v.rsp.attituderaw.accels.y =
|
|
||||||
accel_data.raw.y;
|
|
||||||
user_tx_v1.payload.user.v.rsp.attituderaw.accels.z =
|
|
||||||
accel_data.raw.z;
|
|
||||||
|
|
||||||
user_tx_v1.payload.user.v.rsp.attituderaw.accels_filtered.
|
|
||||||
x = accel_data.filtered.x;
|
|
||||||
user_tx_v1.payload.user.v.rsp.attituderaw.accels_filtered.
|
|
||||||
y = accel_data.filtered.y;
|
|
||||||
user_tx_v1.payload.user.v.rsp.attituderaw.accels_filtered.
|
|
||||||
z = accel_data.filtered.z;
|
|
||||||
|
|
||||||
lfsm_user_set_tx_v1(&user_tx_v1);
|
|
||||||
break;
|
|
||||||
case OPAHRS_MSG_V1_REQ_UPDATE:
|
|
||||||
// process incoming data
|
|
||||||
opahrs_msg_v1_init_user_tx(&user_tx_v1,
|
|
||||||
OPAHRS_MSG_V1_RSP_UPDATE);
|
|
||||||
if (user_rx_v1.payload.user.v.req.update.barometer.updated) {
|
|
||||||
altitude_data.altitude =
|
|
||||||
user_rx_v1.payload.user.v.req.update.barometer.
|
|
||||||
altitude;
|
|
||||||
altitude_data.updated =
|
|
||||||
user_rx_v1.payload.user.v.req.update.barometer.
|
|
||||||
updated;
|
|
||||||
}
|
|
||||||
if (user_rx_v1.payload.user.v.req.update.gps.updated) {
|
|
||||||
gps_data.updated = true;
|
gps_data.updated = true;
|
||||||
gps_data.NED[0] = user_rx_v1.payload.user.v.req.update.gps.NED[0];
|
return;
|
||||||
gps_data.NED[1] = user_rx_v1.payload.user.v.req.update.gps.NED[1];
|
|
||||||
gps_data.NED[2] = user_rx_v1.payload.user.v.req.update.gps.NED[2];
|
|
||||||
gps_data.heading = user_rx_v1.payload.user.v.req.update.gps.heading;
|
|
||||||
gps_data.groundspeed = user_rx_v1.payload.user.v.req.update.gps.groundspeed;
|
|
||||||
gps_data.quality = user_rx_v1.payload.user.v.req.update.gps.quality;
|
|
||||||
}
|
|
||||||
// send out attitude/position estimate
|
|
||||||
user_tx_v1.payload.user.v.rsp.update.quaternion.q1 =
|
|
||||||
attitude_data.quaternion.q1;
|
|
||||||
user_tx_v1.payload.user.v.rsp.update.quaternion.q2 =
|
|
||||||
attitude_data.quaternion.q2;
|
|
||||||
user_tx_v1.payload.user.v.rsp.update.quaternion.q3 =
|
|
||||||
attitude_data.quaternion.q3;
|
|
||||||
user_tx_v1.payload.user.v.rsp.update.quaternion.q4 =
|
|
||||||
attitude_data.quaternion.q4;
|
|
||||||
|
|
||||||
// convert all to cm/s
|
|
||||||
user_tx_v1.payload.user.v.rsp.update.NED[0] = Nav.Pos[0]*100;
|
|
||||||
user_tx_v1.payload.user.v.rsp.update.NED[1] = Nav.Pos[1]*100;
|
|
||||||
user_tx_v1.payload.user.v.rsp.update.NED[2] = Nav.Pos[2]*100;
|
|
||||||
user_tx_v1.payload.user.v.rsp.update.Vel[0] = Nav.Vel[0]*100;
|
|
||||||
user_tx_v1.payload.user.v.rsp.update.Vel[1] = Nav.Vel[1]*100;
|
|
||||||
user_tx_v1.payload.user.v.rsp.update.Vel[2] = Nav.Vel[2]*100;
|
|
||||||
|
|
||||||
// compute the idle fraction
|
|
||||||
user_tx_v1.payload.user.v.rsp.update.load =
|
|
||||||
((float)running_counts /
|
|
||||||
(float)(idle_counts + running_counts)) * 100;
|
|
||||||
user_tx_v1.payload.user.v.rsp.update.idle_time =
|
|
||||||
idle_counts / (TIMER_RATE / 10000);
|
|
||||||
user_tx_v1.payload.user.v.rsp.update.run_time =
|
|
||||||
running_counts / (TIMER_RATE / 10000);
|
|
||||||
user_tx_v1.payload.user.v.rsp.update.dropped_updates =
|
|
||||||
ekf_too_slow;
|
|
||||||
lfsm_user_set_tx_v1(&user_tx_v1);
|
|
||||||
break;
|
|
||||||
case OPAHRS_MSG_V1_REQ_INITIALIZED:
|
|
||||||
// process incoming data
|
|
||||||
opahrs_msg_v1_init_user_tx(&user_tx_v1,OPAHRS_MSG_V1_RSP_INITIALIZED);
|
|
||||||
user_tx_v1.payload.user.v.rsp.initialized.initialized = initialized;
|
|
||||||
if(user_rx_v1.payload.user.v.req.initialized.initialized == AHRS_INITIALIZED)
|
|
||||||
initialized = AHRS_INITIALIZED;
|
|
||||||
else if(user_rx_v1.payload.user.v.req.initialized.initialized == AHRS_UNINITIALIZED)
|
|
||||||
initialized = AHRS_UNINITIALIZED;
|
|
||||||
lfsm_user_set_tx_v1(&user_tx_v1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finished processing the received message, requeue it */
|
double LLA[3] = {(double) pos.Latitude / 1e7, (double) pos.Longitude / 1e7, (double) (pos.GeoidSeparation + pos.Altitude)};
|
||||||
lfsm_user_set_rx_v1(&user_rx_v1);
|
// convert from cm back to meters
|
||||||
lfsm_user_done();
|
double ECEF[3] = {(double) (home.ECEF[0] / 100), (double) (home.ECEF[1] / 100), (double) (home.ECEF[2] / 100)};
|
||||||
|
LLA2Base(LLA, ECEF, (float (*)[3]) home.RNE, gps_data.NED);
|
||||||
|
|
||||||
|
gps_data.heading = pos.Heading;
|
||||||
|
gps_data.groundspeed = pos.Groundspeed;
|
||||||
|
gps_data.quality = 1;
|
||||||
|
gps_data.updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void altitude_callback(AhrsObjHandle obj)
|
||||||
|
{
|
||||||
|
BaroAltitudeData alt;
|
||||||
|
BaroAltitudeGet(&alt);
|
||||||
|
altitude_data.altitude = alt.Altitude;
|
||||||
|
altitude_data.updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void settings_callback(AhrsObjHandle obj)
|
||||||
|
{
|
||||||
|
AHRSSettingsData settings;
|
||||||
|
AHRSSettingsGet(&settings);
|
||||||
|
|
||||||
|
if(settings.Algorithm == AHRSSETTINGS_ALGORITHM_INSGPS)
|
||||||
|
{
|
||||||
|
ahrs_algorithm = INSGPS_Algo;
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
ahrs_algorithm = SIMPLE_Algo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
@ -1,735 +0,0 @@
|
|||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* @addtogroup AHRS AHRS
|
|
||||||
* @brief The AHRS Modules perform
|
|
||||||
*
|
|
||||||
* @{
|
|
||||||
* @addtogroup AHRS_ADC AHRS ADC
|
|
||||||
* @brief Specialized ADC code for double buffered DMA for AHRS
|
|
||||||
* @{
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @file ahrs.c
|
|
||||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
|
||||||
* @brief INSGPS Test Program
|
|
||||||
* @see The GNU Public License (GPL) Version 3
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
/*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h> /* uint*_t */
|
|
||||||
#include <stddef.h> /* NULL */
|
|
||||||
|
|
||||||
#include "ahrs_fsm.h"
|
|
||||||
|
|
||||||
#include "pios_opahrs_proto.h"
|
|
||||||
|
|
||||||
#include "pios.h"
|
|
||||||
|
|
||||||
struct lfsm_context {
|
|
||||||
enum lfsm_state curr_state;
|
|
||||||
enum opahrs_msg_link_state link_state;
|
|
||||||
enum opahrs_msg_type user_payload_type;
|
|
||||||
uint32_t user_payload_len;
|
|
||||||
|
|
||||||
uint32_t errors;
|
|
||||||
|
|
||||||
uint8_t *rx;
|
|
||||||
uint8_t *tx;
|
|
||||||
|
|
||||||
uint8_t *link_rx;
|
|
||||||
uint8_t *link_tx;
|
|
||||||
|
|
||||||
uint8_t *user_rx;
|
|
||||||
uint8_t *user_tx;
|
|
||||||
|
|
||||||
struct lfsm_link_stats stats;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct lfsm_context context = { 0 };
|
|
||||||
|
|
||||||
static void lfsm_update_link_tx(struct lfsm_context *context);
|
|
||||||
static void lfsm_init_rx(struct lfsm_context *context);
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Link Finite State Machine
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct lfsm_transition {
|
|
||||||
void (*entry_fn) (struct lfsm_context * context);
|
|
||||||
enum lfsm_state next_state[LFSM_EVENT_NUM_EVENTS];
|
|
||||||
};
|
|
||||||
|
|
||||||
static void go_faulted(struct lfsm_context *context);
|
|
||||||
static void go_stopped(struct lfsm_context *context);
|
|
||||||
static void go_stopping(struct lfsm_context *context);
|
|
||||||
static void go_inactive(struct lfsm_context *context);
|
|
||||||
static void go_user_busy(struct lfsm_context *context);
|
|
||||||
static void go_user_busy_rx_pending(struct lfsm_context *context);
|
|
||||||
static void go_user_busy_tx_pending(struct lfsm_context *context);
|
|
||||||
static void go_user_busy_rxtx_pending(struct lfsm_context *context);
|
|
||||||
static void go_user_rx_pending(struct lfsm_context *context);
|
|
||||||
static void go_user_tx_pending(struct lfsm_context *context);
|
|
||||||
static void go_user_rxtx_pending(struct lfsm_context *context);
|
|
||||||
static void go_user_rx_active(struct lfsm_context *context);
|
|
||||||
static void go_user_tx_active(struct lfsm_context *context);
|
|
||||||
static void go_user_rxtx_active(struct lfsm_context *context);
|
|
||||||
|
|
||||||
const static struct lfsm_transition lfsm_transitions[LFSM_STATE_NUM_STATES]
|
|
||||||
= {
|
|
||||||
[LFSM_STATE_FAULTED] = {
|
|
||||||
.entry_fn = go_faulted,
|
|
||||||
},
|
|
||||||
[LFSM_STATE_STOPPED] = {
|
|
||||||
.entry_fn = go_stopped,
|
|
||||||
.next_state = {
|
|
||||||
[LFSM_EVENT_INIT_LINK] =
|
|
||||||
LFSM_STATE_INACTIVE,
|
|
||||||
[LFSM_EVENT_RX_UNKNOWN] =
|
|
||||||
LFSM_STATE_STOPPED,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[LFSM_STATE_STOPPING] = {
|
|
||||||
.entry_fn = go_stopping,
|
|
||||||
.next_state = {
|
|
||||||
[LFSM_EVENT_RX_LINK] =
|
|
||||||
LFSM_STATE_STOPPED,
|
|
||||||
[LFSM_EVENT_RX_USER] =
|
|
||||||
LFSM_STATE_STOPPED,
|
|
||||||
[LFSM_EVENT_RX_UNKNOWN] =
|
|
||||||
LFSM_STATE_STOPPED,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[LFSM_STATE_INACTIVE] = {
|
|
||||||
.entry_fn = go_inactive,
|
|
||||||
.next_state = {
|
|
||||||
[LFSM_EVENT_STOP] =
|
|
||||||
LFSM_STATE_STOPPING,
|
|
||||||
[LFSM_EVENT_USER_SET_RX] =
|
|
||||||
LFSM_STATE_USER_BUSY_RX_PENDING,
|
|
||||||
[LFSM_EVENT_USER_SET_TX] =
|
|
||||||
LFSM_STATE_USER_BUSY_TX_PENDING,
|
|
||||||
[LFSM_EVENT_RX_LINK] =
|
|
||||||
LFSM_STATE_INACTIVE,
|
|
||||||
[LFSM_EVENT_RX_USER] =
|
|
||||||
LFSM_STATE_INACTIVE,
|
|
||||||
[LFSM_EVENT_RX_UNKNOWN] =
|
|
||||||
LFSM_STATE_INACTIVE,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[LFSM_STATE_USER_BUSY] = {
|
|
||||||
.entry_fn = go_user_busy,
|
|
||||||
.next_state = {
|
|
||||||
[LFSM_EVENT_STOP] =
|
|
||||||
LFSM_STATE_STOPPING,
|
|
||||||
[LFSM_EVENT_USER_SET_RX] =
|
|
||||||
LFSM_STATE_USER_BUSY_RX_PENDING,
|
|
||||||
[LFSM_EVENT_USER_SET_TX] =
|
|
||||||
LFSM_STATE_USER_BUSY_TX_PENDING,
|
|
||||||
[LFSM_EVENT_USER_DONE] =
|
|
||||||
LFSM_STATE_INACTIVE,
|
|
||||||
[LFSM_EVENT_RX_LINK] =
|
|
||||||
LFSM_STATE_USER_BUSY,
|
|
||||||
[LFSM_EVENT_RX_USER] =
|
|
||||||
LFSM_STATE_USER_BUSY,
|
|
||||||
[LFSM_EVENT_RX_UNKNOWN] =
|
|
||||||
LFSM_STATE_USER_BUSY,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[LFSM_STATE_USER_BUSY_RX_PENDING] = {
|
|
||||||
.entry_fn =
|
|
||||||
go_user_busy_rx_pending,
|
|
||||||
.next_state = {
|
|
||||||
[LFSM_EVENT_USER_SET_TX] = LFSM_STATE_USER_BUSY_RXTX_PENDING,
|
|
||||||
[LFSM_EVENT_USER_DONE] = LFSM_STATE_USER_RX_PENDING,
|
|
||||||
[LFSM_EVENT_RX_LINK] = LFSM_STATE_USER_BUSY_RX_PENDING,
|
|
||||||
[LFSM_EVENT_RX_USER] = LFSM_STATE_USER_BUSY_RX_PENDING,
|
|
||||||
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_USER_BUSY_RX_PENDING,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[LFSM_STATE_USER_BUSY_TX_PENDING] = {
|
|
||||||
.entry_fn =
|
|
||||||
go_user_busy_tx_pending,
|
|
||||||
.next_state = {
|
|
||||||
[LFSM_EVENT_USER_SET_RX] = LFSM_STATE_USER_BUSY_RXTX_PENDING,
|
|
||||||
[LFSM_EVENT_USER_DONE] = LFSM_STATE_USER_TX_PENDING,
|
|
||||||
[LFSM_EVENT_RX_LINK] = LFSM_STATE_USER_BUSY_TX_PENDING,
|
|
||||||
[LFSM_EVENT_RX_USER] = LFSM_STATE_USER_BUSY_TX_PENDING,
|
|
||||||
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_USER_BUSY_TX_PENDING,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[LFSM_STATE_USER_BUSY_RXTX_PENDING] = {
|
|
||||||
.entry_fn =
|
|
||||||
go_user_busy_rxtx_pending,
|
|
||||||
.next_state = {
|
|
||||||
[LFSM_EVENT_USER_DONE] = LFSM_STATE_USER_RXTX_PENDING,
|
|
||||||
[LFSM_EVENT_RX_LINK] = LFSM_STATE_USER_BUSY_RXTX_PENDING,
|
|
||||||
[LFSM_EVENT_RX_USER] = LFSM_STATE_USER_BUSY_RXTX_PENDING,
|
|
||||||
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_USER_BUSY_RXTX_PENDING,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[LFSM_STATE_USER_RX_PENDING] = {
|
|
||||||
.entry_fn = go_user_rx_pending,
|
|
||||||
.next_state = {
|
|
||||||
[LFSM_EVENT_RX_LINK]
|
|
||||||
=
|
|
||||||
LFSM_STATE_USER_RX_ACTIVE,
|
|
||||||
[LFSM_EVENT_RX_USER]
|
|
||||||
=
|
|
||||||
LFSM_STATE_USER_RX_ACTIVE,
|
|
||||||
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_USER_RX_ACTIVE,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[LFSM_STATE_USER_TX_PENDING] = {
|
|
||||||
.entry_fn = go_user_tx_pending,
|
|
||||||
.next_state = {
|
|
||||||
[LFSM_EVENT_RX_LINK]
|
|
||||||
=
|
|
||||||
LFSM_STATE_USER_TX_ACTIVE,
|
|
||||||
[LFSM_EVENT_RX_USER]
|
|
||||||
=
|
|
||||||
LFSM_STATE_USER_TX_ACTIVE,
|
|
||||||
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_USER_TX_ACTIVE,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[LFSM_STATE_USER_RXTX_PENDING] = {
|
|
||||||
.entry_fn = go_user_rxtx_pending,
|
|
||||||
.next_state = {
|
|
||||||
[LFSM_EVENT_RX_LINK] = LFSM_STATE_USER_RXTX_ACTIVE,
|
|
||||||
[LFSM_EVENT_RX_USER] = LFSM_STATE_USER_RXTX_ACTIVE,
|
|
||||||
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_USER_RXTX_ACTIVE,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[LFSM_STATE_USER_RX_ACTIVE] = {
|
|
||||||
.entry_fn = go_user_rx_active,
|
|
||||||
.next_state = {
|
|
||||||
[LFSM_EVENT_RX_LINK]
|
|
||||||
=
|
|
||||||
LFSM_STATE_USER_RX_ACTIVE,
|
|
||||||
[LFSM_EVENT_RX_USER]
|
|
||||||
=
|
|
||||||
LFSM_STATE_USER_BUSY,
|
|
||||||
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_USER_RX_ACTIVE,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[LFSM_STATE_USER_TX_ACTIVE] = {
|
|
||||||
.entry_fn = go_user_tx_active,
|
|
||||||
.next_state = {
|
|
||||||
[LFSM_EVENT_RX_LINK]
|
|
||||||
=
|
|
||||||
LFSM_STATE_INACTIVE,
|
|
||||||
[LFSM_EVENT_RX_USER]
|
|
||||||
=
|
|
||||||
LFSM_STATE_INACTIVE,
|
|
||||||
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_INACTIVE,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[LFSM_STATE_USER_RXTX_ACTIVE] = {
|
|
||||||
.entry_fn = go_user_rxtx_active,
|
|
||||||
.next_state = {
|
|
||||||
[LFSM_EVENT_RX_LINK] = LFSM_STATE_USER_RX_ACTIVE,
|
|
||||||
[LFSM_EVENT_RX_USER] = LFSM_STATE_USER_BUSY,
|
|
||||||
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_USER_RX_ACTIVE,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* FSM State Entry Functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void go_faulted(struct lfsm_context *context)
|
|
||||||
{
|
|
||||||
PIOS_DEBUG_Assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void go_stopped(struct lfsm_context *context)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
PIOS_SPI_Stop(PIOS_SPI_OP);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void go_stopping(struct lfsm_context *context)
|
|
||||||
{
|
|
||||||
context->link_tx = NULL;
|
|
||||||
context->tx = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void go_inactive(struct lfsm_context *context)
|
|
||||||
{
|
|
||||||
context->link_state = OPAHRS_MSG_LINK_STATE_INACTIVE;
|
|
||||||
lfsm_update_link_tx(context);
|
|
||||||
|
|
||||||
context->user_rx = NULL;
|
|
||||||
context->user_tx = NULL;
|
|
||||||
|
|
||||||
context->rx = context->link_rx;
|
|
||||||
context->tx = context->link_tx;
|
|
||||||
|
|
||||||
lfsm_init_rx(context);
|
|
||||||
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
||||||
context->user_payload_len,
|
|
||||||
lfsm_irq_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void go_user_busy(struct lfsm_context *context)
|
|
||||||
{
|
|
||||||
/* Sanity checks */
|
|
||||||
PIOS_DEBUG_Assert(context->user_rx);
|
|
||||||
|
|
||||||
context->user_rx = NULL;
|
|
||||||
context->user_tx = NULL;
|
|
||||||
|
|
||||||
context->link_state = OPAHRS_MSG_LINK_STATE_BUSY;
|
|
||||||
lfsm_update_link_tx(context);
|
|
||||||
|
|
||||||
context->rx = context->link_rx;
|
|
||||||
context->tx = context->link_tx;
|
|
||||||
|
|
||||||
lfsm_init_rx(context);
|
|
||||||
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
||||||
context->user_payload_len,
|
|
||||||
lfsm_irq_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void go_user_busy_rx_pending(struct lfsm_context *context)
|
|
||||||
{
|
|
||||||
/* Sanity checks */
|
|
||||||
PIOS_DEBUG_Assert(context->user_rx);
|
|
||||||
|
|
||||||
context->link_state = OPAHRS_MSG_LINK_STATE_BUSY;
|
|
||||||
lfsm_update_link_tx(context);
|
|
||||||
|
|
||||||
context->rx = context->link_rx;
|
|
||||||
context->tx = context->link_tx;
|
|
||||||
|
|
||||||
lfsm_init_rx(context);
|
|
||||||
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
||||||
context->user_payload_len,
|
|
||||||
lfsm_irq_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void go_user_busy_tx_pending(struct lfsm_context *context)
|
|
||||||
{
|
|
||||||
/* Sanity checks */
|
|
||||||
PIOS_DEBUG_Assert(context->user_tx);
|
|
||||||
|
|
||||||
context->link_state = OPAHRS_MSG_LINK_STATE_BUSY;
|
|
||||||
lfsm_update_link_tx(context);
|
|
||||||
|
|
||||||
context->rx = context->link_rx;
|
|
||||||
context->tx = context->link_tx;
|
|
||||||
|
|
||||||
lfsm_init_rx(context);
|
|
||||||
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
||||||
context->user_payload_len,
|
|
||||||
lfsm_irq_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void go_user_busy_rxtx_pending(struct lfsm_context *context)
|
|
||||||
{
|
|
||||||
/* Sanity checks */
|
|
||||||
PIOS_DEBUG_Assert(context->user_rx);
|
|
||||||
PIOS_DEBUG_Assert(context->user_tx);
|
|
||||||
|
|
||||||
context->link_state = OPAHRS_MSG_LINK_STATE_BUSY;
|
|
||||||
lfsm_update_link_tx(context);
|
|
||||||
|
|
||||||
context->rx = context->link_rx;
|
|
||||||
context->tx = context->link_tx;
|
|
||||||
|
|
||||||
lfsm_init_rx(context);
|
|
||||||
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
||||||
context->user_payload_len,
|
|
||||||
lfsm_irq_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void go_user_rx_pending(struct lfsm_context *context)
|
|
||||||
{
|
|
||||||
/* Sanity checks */
|
|
||||||
PIOS_DEBUG_Assert(context->user_rx);
|
|
||||||
|
|
||||||
context->link_state = OPAHRS_MSG_LINK_STATE_BUSY;
|
|
||||||
lfsm_update_link_tx(context);
|
|
||||||
|
|
||||||
context->rx = context->link_rx;
|
|
||||||
context->tx = context->link_tx;
|
|
||||||
|
|
||||||
lfsm_init_rx(context);
|
|
||||||
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
||||||
context->user_payload_len,
|
|
||||||
lfsm_irq_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void go_user_tx_pending(struct lfsm_context *context)
|
|
||||||
{
|
|
||||||
/* Sanity checks */
|
|
||||||
PIOS_DEBUG_Assert(context->user_tx);
|
|
||||||
|
|
||||||
context->link_state = OPAHRS_MSG_LINK_STATE_BUSY;
|
|
||||||
lfsm_update_link_tx(context);
|
|
||||||
|
|
||||||
context->rx = context->link_rx;
|
|
||||||
context->tx = context->link_tx;
|
|
||||||
|
|
||||||
lfsm_init_rx(context);
|
|
||||||
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
||||||
context->user_payload_len,
|
|
||||||
lfsm_irq_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void go_user_rxtx_pending(struct lfsm_context *context)
|
|
||||||
{
|
|
||||||
/* Sanity checks */
|
|
||||||
PIOS_DEBUG_Assert(context->user_rx);
|
|
||||||
PIOS_DEBUG_Assert(context->user_tx);
|
|
||||||
|
|
||||||
context->link_state = OPAHRS_MSG_LINK_STATE_BUSY;
|
|
||||||
lfsm_update_link_tx(context);
|
|
||||||
|
|
||||||
context->rx = context->link_rx;
|
|
||||||
context->tx = context->link_tx;
|
|
||||||
|
|
||||||
lfsm_init_rx(context);
|
|
||||||
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
||||||
context->user_payload_len,
|
|
||||||
lfsm_irq_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void go_user_rx_active(struct lfsm_context *context)
|
|
||||||
{
|
|
||||||
/* Sanity checks */
|
|
||||||
PIOS_DEBUG_Assert(context->user_rx);
|
|
||||||
|
|
||||||
context->rx = context->user_rx;
|
|
||||||
context->tx = context->link_tx;
|
|
||||||
context->link_state = OPAHRS_MSG_LINK_STATE_READY;
|
|
||||||
|
|
||||||
lfsm_update_link_tx(context);
|
|
||||||
lfsm_init_rx(context);
|
|
||||||
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
||||||
context->user_payload_len,
|
|
||||||
lfsm_irq_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void go_user_tx_active(struct lfsm_context *context)
|
|
||||||
{
|
|
||||||
/* Sanity checks */
|
|
||||||
PIOS_DEBUG_Assert(context->user_tx);
|
|
||||||
|
|
||||||
context->link_state = OPAHRS_MSG_LINK_STATE_BUSY;
|
|
||||||
context->rx = context->link_rx;
|
|
||||||
context->tx = context->user_tx;
|
|
||||||
|
|
||||||
lfsm_init_rx(context);
|
|
||||||
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
||||||
context->user_payload_len,
|
|
||||||
lfsm_irq_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void go_user_rxtx_active(struct lfsm_context *context)
|
|
||||||
{
|
|
||||||
/* Sanity checks */
|
|
||||||
PIOS_DEBUG_Assert(context->user_rx);
|
|
||||||
PIOS_DEBUG_Assert(context->user_tx);
|
|
||||||
|
|
||||||
context->link_state = OPAHRS_MSG_LINK_STATE_READY;
|
|
||||||
context->rx = context->user_rx;
|
|
||||||
context->tx = context->user_tx;
|
|
||||||
|
|
||||||
lfsm_init_rx(context);
|
|
||||||
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
||||||
context->user_payload_len,
|
|
||||||
lfsm_irq_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Misc Helper Functions
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void lfsm_update_link_tx_v0(struct opahrs_msg_v0 *msg,
|
|
||||||
enum opahrs_msg_link_state state,
|
|
||||||
uint16_t errors)
|
|
||||||
{
|
|
||||||
opahrs_msg_v0_init_link_tx(msg, OPAHRS_MSG_LINK_TAG_NOP);
|
|
||||||
|
|
||||||
msg->payload.link.state = state;
|
|
||||||
msg->payload.link.errors = errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lfsm_update_link_tx_v1(struct opahrs_msg_v1 *msg,
|
|
||||||
enum opahrs_msg_link_state state,
|
|
||||||
uint16_t errors)
|
|
||||||
{
|
|
||||||
opahrs_msg_v1_init_link_tx(msg, OPAHRS_MSG_LINK_TAG_NOP);
|
|
||||||
|
|
||||||
msg->payload.link.state = state;
|
|
||||||
msg->payload.link.errors = errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lfsm_update_link_tx(struct lfsm_context *context)
|
|
||||||
{
|
|
||||||
PIOS_DEBUG_Assert(context->link_tx);
|
|
||||||
|
|
||||||
switch (context->user_payload_type) {
|
|
||||||
case OPAHRS_MSG_TYPE_USER_V0:
|
|
||||||
lfsm_update_link_tx_v0((struct opahrs_msg_v0 *)context->
|
|
||||||
link_tx, context->link_state,
|
|
||||||
context->errors);
|
|
||||||
break;
|
|
||||||
case OPAHRS_MSG_TYPE_USER_V1:
|
|
||||||
lfsm_update_link_tx_v1((struct opahrs_msg_v1 *)context->
|
|
||||||
link_tx, context->link_state,
|
|
||||||
context->errors);
|
|
||||||
break;
|
|
||||||
case OPAHRS_MSG_TYPE_LINK:
|
|
||||||
PIOS_DEBUG_Assert(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lfsm_init_rx(struct lfsm_context *context)
|
|
||||||
{
|
|
||||||
PIOS_DEBUG_Assert(context->rx);
|
|
||||||
|
|
||||||
switch (context->user_payload_type) {
|
|
||||||
case OPAHRS_MSG_TYPE_USER_V0:
|
|
||||||
opahrs_msg_v0_init_rx((struct opahrs_msg_v0 *)context->rx);
|
|
||||||
break;
|
|
||||||
case OPAHRS_MSG_TYPE_USER_V1:
|
|
||||||
opahrs_msg_v1_init_rx((struct opahrs_msg_v1 *)context->rx);
|
|
||||||
break;
|
|
||||||
case OPAHRS_MSG_TYPE_LINK:
|
|
||||||
PIOS_DEBUG_Assert(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* External API
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
void lfsm_inject_event(enum lfsm_event event)
|
|
||||||
{
|
|
||||||
PIOS_IRQ_Disable();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Move to the next state
|
|
||||||
*
|
|
||||||
* This is done prior to calling the new state's entry function to
|
|
||||||
* guarantee that the entry function never depends on the previous
|
|
||||||
* state. This way, it cannot ever know what the previous state was.
|
|
||||||
*/
|
|
||||||
context.curr_state =
|
|
||||||
lfsm_transitions[context.curr_state].next_state[event];
|
|
||||||
|
|
||||||
/* Call the entry function (if any) for the next state. */
|
|
||||||
if (lfsm_transitions[context.curr_state].entry_fn) {
|
|
||||||
lfsm_transitions[context.curr_state].entry_fn(&context);
|
|
||||||
}
|
|
||||||
PIOS_IRQ_Enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
void lfsm_init(void)
|
|
||||||
{
|
|
||||||
context.curr_state = LFSM_STATE_STOPPED;
|
|
||||||
go_stopped(&context);
|
|
||||||
}
|
|
||||||
|
|
||||||
void lfsm_set_link_proto_v0(struct opahrs_msg_v0 *link_tx,
|
|
||||||
struct opahrs_msg_v0 *link_rx)
|
|
||||||
{
|
|
||||||
PIOS_DEBUG_Assert(link_tx);
|
|
||||||
|
|
||||||
context.link_tx = (uint8_t *) link_tx;
|
|
||||||
context.link_rx = (uint8_t *) link_rx;
|
|
||||||
context.user_payload_type = OPAHRS_MSG_TYPE_USER_V0;
|
|
||||||
context.user_payload_len = sizeof(*link_tx);
|
|
||||||
|
|
||||||
lfsm_update_link_tx_v0(link_tx, context.link_state,
|
|
||||||
context.errors);
|
|
||||||
|
|
||||||
lfsm_inject_event(LFSM_EVENT_INIT_LINK);
|
|
||||||
}
|
|
||||||
|
|
||||||
void lfsm_set_link_proto_v1(struct opahrs_msg_v1 *link_tx,
|
|
||||||
struct opahrs_msg_v1 *link_rx)
|
|
||||||
{
|
|
||||||
PIOS_DEBUG_Assert(link_tx);
|
|
||||||
|
|
||||||
context.link_tx = (uint8_t *) link_tx;
|
|
||||||
context.link_rx = (uint8_t *) link_rx;
|
|
||||||
context.user_payload_type = OPAHRS_MSG_TYPE_USER_V1;
|
|
||||||
context.user_payload_len = sizeof(*link_tx);
|
|
||||||
|
|
||||||
lfsm_update_link_tx_v1(link_tx, context.link_state,
|
|
||||||
context.errors);
|
|
||||||
|
|
||||||
lfsm_inject_event(LFSM_EVENT_INIT_LINK);
|
|
||||||
}
|
|
||||||
|
|
||||||
void lfsm_user_set_tx_v0(struct opahrs_msg_v0 *user_tx)
|
|
||||||
{
|
|
||||||
PIOS_DEBUG_Assert(user_tx);
|
|
||||||
|
|
||||||
PIOS_DEBUG_Assert(context.user_payload_type ==
|
|
||||||
OPAHRS_MSG_TYPE_USER_V0);
|
|
||||||
context.user_tx = (uint8_t *) user_tx;
|
|
||||||
|
|
||||||
lfsm_inject_event(LFSM_EVENT_USER_SET_TX);
|
|
||||||
}
|
|
||||||
|
|
||||||
void lfsm_user_set_rx_v0(struct opahrs_msg_v0 *user_rx)
|
|
||||||
{
|
|
||||||
PIOS_DEBUG_Assert(user_rx);
|
|
||||||
PIOS_DEBUG_Assert(context.user_payload_type ==
|
|
||||||
OPAHRS_MSG_TYPE_USER_V0);
|
|
||||||
|
|
||||||
context.user_rx = (uint8_t *) user_rx;
|
|
||||||
|
|
||||||
lfsm_inject_event(LFSM_EVENT_USER_SET_RX);
|
|
||||||
}
|
|
||||||
|
|
||||||
void lfsm_user_set_tx_v1(struct opahrs_msg_v1 *user_tx)
|
|
||||||
{
|
|
||||||
PIOS_DEBUG_Assert(user_tx);
|
|
||||||
PIOS_DEBUG_Assert(context.user_payload_type ==
|
|
||||||
OPAHRS_MSG_TYPE_USER_V1);
|
|
||||||
|
|
||||||
context.user_tx = (uint8_t *) user_tx;
|
|
||||||
|
|
||||||
lfsm_inject_event(LFSM_EVENT_USER_SET_TX);
|
|
||||||
}
|
|
||||||
|
|
||||||
void lfsm_user_set_rx_v1(struct opahrs_msg_v1 *user_rx)
|
|
||||||
{
|
|
||||||
PIOS_DEBUG_Assert(user_rx);
|
|
||||||
PIOS_DEBUG_Assert(context.user_payload_type ==
|
|
||||||
OPAHRS_MSG_TYPE_USER_V1);
|
|
||||||
|
|
||||||
context.user_rx = (uint8_t *) user_rx;
|
|
||||||
|
|
||||||
lfsm_inject_event(LFSM_EVENT_USER_SET_RX);
|
|
||||||
}
|
|
||||||
|
|
||||||
void lfsm_user_done(void)
|
|
||||||
{
|
|
||||||
lfsm_inject_event(LFSM_EVENT_USER_DONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void lfsm_stop(void)
|
|
||||||
{
|
|
||||||
lfsm_inject_event(LFSM_EVENT_STOP);
|
|
||||||
}
|
|
||||||
|
|
||||||
void lfsm_get_link_stats(struct lfsm_link_stats *stats)
|
|
||||||
{
|
|
||||||
PIOS_DEBUG_Assert(stats);
|
|
||||||
|
|
||||||
*stats = context.stats;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum lfsm_state lfsm_get_state(void)
|
|
||||||
{
|
|
||||||
return context.curr_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* ISR Callback
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
void lfsm_irq_callback(uint8_t crc_ok, uint8_t crc_val)
|
|
||||||
{
|
|
||||||
if (!crc_ok) {
|
|
||||||
context.stats.rx_badcrc++;
|
|
||||||
lfsm_inject_event(LFSM_EVENT_RX_UNKNOWN);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!context.rx) {
|
|
||||||
/* No way to know what we just received, assume invalid */
|
|
||||||
lfsm_inject_event(LFSM_EVENT_RX_UNKNOWN);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Recover the head and tail pointers from the message */
|
|
||||||
struct opahrs_msg_link_head *head = NULL;
|
|
||||||
struct opahrs_msg_link_tail *tail = NULL;
|
|
||||||
|
|
||||||
switch (context.user_payload_type) {
|
|
||||||
case OPAHRS_MSG_TYPE_USER_V0:
|
|
||||||
head = &((struct opahrs_msg_v0 *)context.rx)->head;
|
|
||||||
tail = &((struct opahrs_msg_v0 *)context.rx)->tail;
|
|
||||||
break;
|
|
||||||
case OPAHRS_MSG_TYPE_USER_V1:
|
|
||||||
head = &((struct opahrs_msg_v1 *)context.rx)->head;
|
|
||||||
tail = &((struct opahrs_msg_v1 *)context.rx)->tail;
|
|
||||||
break;
|
|
||||||
case OPAHRS_MSG_TYPE_LINK:
|
|
||||||
/* Should never be rx'ing before the link protocol version is known */
|
|
||||||
PIOS_DEBUG_Assert(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for bad magic */
|
|
||||||
if ((head->magic != OPAHRS_MSG_MAGIC_HEAD) ||
|
|
||||||
(tail->magic != OPAHRS_MSG_MAGIC_TAIL)) {
|
|
||||||
if (head->magic != OPAHRS_MSG_MAGIC_HEAD) {
|
|
||||||
context.stats.rx_badmagic_head++;
|
|
||||||
}
|
|
||||||
if (tail->magic != OPAHRS_MSG_MAGIC_TAIL) {
|
|
||||||
context.stats.rx_badmagic_tail++;
|
|
||||||
}
|
|
||||||
lfsm_inject_event(LFSM_EVENT_RX_UNKNOWN);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Good magic, find out what type of payload we've got */
|
|
||||||
switch (head->type) {
|
|
||||||
case OPAHRS_MSG_TYPE_LINK:
|
|
||||||
context.stats.rx_link++;
|
|
||||||
lfsm_inject_event(LFSM_EVENT_RX_LINK);
|
|
||||||
break;
|
|
||||||
case OPAHRS_MSG_TYPE_USER_V0:
|
|
||||||
case OPAHRS_MSG_TYPE_USER_V1:
|
|
||||||
if (head->type == context.user_payload_type) {
|
|
||||||
context.stats.rx_user++;
|
|
||||||
lfsm_inject_event(LFSM_EVENT_RX_USER);
|
|
||||||
} else {
|
|
||||||
/* Mismatched user payload type */
|
|
||||||
context.stats.rx_badver++;
|
|
||||||
lfsm_inject_event(LFSM_EVENT_RX_UNKNOWN);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* Unidentifiable payload type */
|
|
||||||
context.stats.rx_badtype++;
|
|
||||||
lfsm_inject_event(LFSM_EVENT_RX_UNKNOWN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
* @}
|
|
||||||
*/
|
|
@ -1,853 +0,0 @@
|
|||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* @addtogroup AHRS AHRS
|
|
||||||
* @brief The AHRS Modules perform
|
|
||||||
*
|
|
||||||
* @{
|
|
||||||
* @addtogroup AHRS_Main
|
|
||||||
* @brief Main function which does the hardware dependent stuff
|
|
||||||
* @{
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @file ahrs.c
|
|
||||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
|
||||||
* @brief INSGPS Test Program
|
|
||||||
* @see The GNU Public License (GPL) Version 3
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
/*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* OpenPilot Includes */
|
|
||||||
#include "ahrs.h"
|
|
||||||
#include "ahrs_adc.h"
|
|
||||||
#include "ahrs_timer.h"
|
|
||||||
#include "pios_opahrs_proto.h"
|
|
||||||
//#include "ahrs_fsm.h" /* lfsm_state */
|
|
||||||
#include "insgps.h"
|
|
||||||
#include "CoordinateConversions.h"
|
|
||||||
#include "ahrs_spi_comm.h"
|
|
||||||
|
|
||||||
// For debugging the raw sensors
|
|
||||||
//#define DUMP_RAW
|
|
||||||
//#define DUMP_FRIENDLY
|
|
||||||
//#define DUMP_EKF
|
|
||||||
|
|
||||||
#ifdef DUMP_EKF
|
|
||||||
#define NUMX 13 // number of states, X is the state vector
|
|
||||||
#define NUMW 9 // number of plant noise inputs, w is disturbance noise vector
|
|
||||||
#define NUMV 10 // number of measurements, v is the measurement noise vector
|
|
||||||
#define NUMU 6 // number of deterministic inputs, U is the input vector
|
|
||||||
extern float F[NUMX][NUMX], G[NUMX][NUMW], H[NUMV][NUMX]; // linearized system matrices
|
|
||||||
extern float P[NUMX][NUMX], X[NUMX]; // covariance matrix and state vector
|
|
||||||
extern float Q[NUMW], R[NUMV]; // input noise and measurement noise variances
|
|
||||||
extern float K[NUMX][NUMV]; // feedback gain matrix
|
|
||||||
#endif
|
|
||||||
|
|
||||||
volatile enum algorithms ahrs_algorithm;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @addtogroup AHRS_Structures Local Structres
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
//! Contains the data from the mag sensor chip
|
|
||||||
struct mag_sensor {
|
|
||||||
uint8_t id[4];
|
|
||||||
uint8_t updated;
|
|
||||||
struct {
|
|
||||||
int16_t axis[3];
|
|
||||||
} raw;
|
|
||||||
struct {
|
|
||||||
float axis[3];
|
|
||||||
} scaled;
|
|
||||||
struct {
|
|
||||||
float bias[3];
|
|
||||||
float scale[3];
|
|
||||||
float variance[3];
|
|
||||||
} calibration;
|
|
||||||
} mag_data;
|
|
||||||
|
|
||||||
//! Contains the data from the accelerometer
|
|
||||||
struct accel_sensor {
|
|
||||||
struct {
|
|
||||||
uint16_t x;
|
|
||||||
uint16_t y;
|
|
||||||
uint16_t z;
|
|
||||||
} raw;
|
|
||||||
struct {
|
|
||||||
float x;
|
|
||||||
float y;
|
|
||||||
float z;
|
|
||||||
} filtered;
|
|
||||||
struct {
|
|
||||||
float bias[3];
|
|
||||||
float scale[3];
|
|
||||||
float variance[3];
|
|
||||||
} calibration;
|
|
||||||
} accel_data;
|
|
||||||
|
|
||||||
//! Contains the data from the gyro
|
|
||||||
struct gyro_sensor {
|
|
||||||
struct {
|
|
||||||
uint16_t x;
|
|
||||||
uint16_t y;
|
|
||||||
uint16_t z;
|
|
||||||
} raw;
|
|
||||||
struct {
|
|
||||||
float x;
|
|
||||||
float y;
|
|
||||||
float z;
|
|
||||||
} filtered;
|
|
||||||
struct {
|
|
||||||
float bias[3];
|
|
||||||
float scale[3];
|
|
||||||
float variance[3];
|
|
||||||
} calibration;
|
|
||||||
struct {
|
|
||||||
uint16_t xy;
|
|
||||||
uint16_t z;
|
|
||||||
} temp;
|
|
||||||
} gyro_data;
|
|
||||||
|
|
||||||
//! Conains the current estimate of the attitude
|
|
||||||
struct attitude_solution {
|
|
||||||
struct {
|
|
||||||
float q1;
|
|
||||||
float q2;
|
|
||||||
float q3;
|
|
||||||
float q4;
|
|
||||||
} quaternion;
|
|
||||||
} attitude_data;
|
|
||||||
|
|
||||||
//! Contains data from the altitude sensor
|
|
||||||
struct altitude_sensor {
|
|
||||||
float altitude;
|
|
||||||
bool updated;
|
|
||||||
} altitude_data;
|
|
||||||
|
|
||||||
//! Contains data from the GPS (via the SPI link)
|
|
||||||
struct gps_sensor {
|
|
||||||
float NED[3];
|
|
||||||
float heading;
|
|
||||||
float groundspeed;
|
|
||||||
float quality;
|
|
||||||
bool updated;
|
|
||||||
} gps_data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Function Prototypes */
|
|
||||||
void process_spi_request(void);
|
|
||||||
void downsample_data(void);
|
|
||||||
void calibrate_sensors(void);
|
|
||||||
void reset_values();
|
|
||||||
void send_calibration(void);
|
|
||||||
void altitude_callback(AhrsObjHandle obj);
|
|
||||||
void calibration_callback(AhrsObjHandle obj);
|
|
||||||
void gps_callback(AhrsObjHandle obj);
|
|
||||||
void settings_callback(AhrsObjHandle obj);
|
|
||||||
|
|
||||||
volatile uint32_t last_counter_idle_start = 0;
|
|
||||||
volatile uint32_t last_counter_idle_end = 0;
|
|
||||||
volatile uint32_t idle_counts;
|
|
||||||
volatile uint32_t running_counts;
|
|
||||||
uint32_t counter_val;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @addtogroup AHRS_Global_Data AHRS Global Data
|
|
||||||
* @{
|
|
||||||
* Public data. Used by both EKF and the sender
|
|
||||||
*/
|
|
||||||
//! Filter coefficients used in decimation. Limited order so filter can't run between samples
|
|
||||||
int16_t fir_coeffs[50];
|
|
||||||
|
|
||||||
|
|
||||||
//! The oversampling rate, ekf is 2k / this
|
|
||||||
static uint8_t adc_oversampling = 17;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief AHRS Main function
|
|
||||||
*/
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
float gyro[3], accel[3], mag[3];
|
|
||||||
float vel[3] = { 0, 0, 0 };
|
|
||||||
gps_data.quality = -1;
|
|
||||||
|
|
||||||
ahrs_algorithm = INSGPS_Algo;
|
|
||||||
|
|
||||||
/* Brings up System using CMSIS functions, enables the LEDs. */
|
|
||||||
PIOS_SYS_Init();
|
|
||||||
|
|
||||||
/* Delay system */
|
|
||||||
PIOS_DELAY_Init();
|
|
||||||
|
|
||||||
/* Communication system */
|
|
||||||
PIOS_COM_Init();
|
|
||||||
|
|
||||||
/* ADC system */
|
|
||||||
AHRS_ADC_Config(adc_oversampling);
|
|
||||||
|
|
||||||
/* Setup the Accelerometer FS (Full-Scale) GPIO */
|
|
||||||
PIOS_GPIO_Enable(0);
|
|
||||||
SET_ACCEL_2G;
|
|
||||||
#if defined(PIOS_INCLUDE_HMC5843) && defined(PIOS_INCLUDE_I2C)
|
|
||||||
/* Magnetic sensor system */
|
|
||||||
PIOS_I2C_Init();
|
|
||||||
PIOS_HMC5843_Init();
|
|
||||||
// Get 3 ID bytes
|
|
||||||
strcpy((char *)mag_data.id, "ZZZ");
|
|
||||||
PIOS_HMC5843_ReadID(mag_data.id);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* SPI link to master */
|
|
||||||
// PIOS_SPI_Init();
|
|
||||||
|
|
||||||
// lfsm_init();
|
|
||||||
reset_values();
|
|
||||||
|
|
||||||
ahrs_state = AHRS_IDLE;
|
|
||||||
AhrsInitComms();
|
|
||||||
ahrs_state = AHRS_IDLE;
|
|
||||||
while(!AhrsLinkReady()) {
|
|
||||||
AhrsPoll();
|
|
||||||
while(ahrs_state != AHRS_DATA_READY) ;
|
|
||||||
ahrs_state = AHRS_PROCESSING;
|
|
||||||
downsample_data();
|
|
||||||
ahrs_state = AHRS_IDLE;
|
|
||||||
if((total_conversion_blocks % 10) == 0)
|
|
||||||
PIOS_LED_Toggle(LED1);
|
|
||||||
}
|
|
||||||
/* we didn't connect the callbacks before because we have to wait
|
|
||||||
for all data to be up to date before doing anything*/
|
|
||||||
AHRSCalibrationConnectCallback(calibration_callback);
|
|
||||||
GPSPositionConnectCallback(gps_callback);
|
|
||||||
BaroAltitudeConnectCallback(altitude_callback);
|
|
||||||
AHRSSettingsConnectCallback(settings_callback);
|
|
||||||
|
|
||||||
calibration_callback(AHRSCalibrationHandle()); //force an update
|
|
||||||
|
|
||||||
|
|
||||||
/* Use simple averaging filter for now */
|
|
||||||
for (int i = 0; i < adc_oversampling; i++)
|
|
||||||
fir_coeffs[i] = 1;
|
|
||||||
fir_coeffs[adc_oversampling] = adc_oversampling;
|
|
||||||
|
|
||||||
INSGPSInit();
|
|
||||||
|
|
||||||
#ifdef DUMP_RAW
|
|
||||||
int previous_conversion;
|
|
||||||
while (1) {
|
|
||||||
AhrsPoll();
|
|
||||||
int result;
|
|
||||||
uint8_t framing[16] =
|
|
||||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
|
||||||
15 };
|
|
||||||
while (ahrs_state != AHRS_DATA_READY) ;
|
|
||||||
ahrs_state = AHRS_PROCESSING;
|
|
||||||
|
|
||||||
if (total_conversion_blocks != previous_conversion + 1)
|
|
||||||
PIOS_LED_On(LED1); // not keeping up
|
|
||||||
else
|
|
||||||
PIOS_LED_Off(LED1);
|
|
||||||
previous_conversion = total_conversion_blocks;
|
|
||||||
|
|
||||||
downsample_data();
|
|
||||||
ahrs_state = AHRS_IDLE;;
|
|
||||||
|
|
||||||
// Dump raw buffer
|
|
||||||
result = PIOS_COM_SendBuffer(PIOS_COM_AUX, &framing[0], 16); // framing header
|
|
||||||
result += PIOS_COM_SendBuffer(PIOS_COM_AUX, (uint8_t *) & total_conversion_blocks, sizeof(total_conversion_blocks)); // dump block number
|
|
||||||
result +=
|
|
||||||
PIOS_COM_SendBuffer(PIOS_COM_AUX,
|
|
||||||
(uint8_t *) & valid_data_buffer[0],
|
|
||||||
adc_oversampling *
|
|
||||||
ADC_CONTINUOUS_CHANNELS *
|
|
||||||
sizeof(valid_data_buffer[0]));
|
|
||||||
if (result == 0)
|
|
||||||
PIOS_LED_Off(LED1);
|
|
||||||
else {
|
|
||||||
PIOS_LED_On(LED1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
timer_start();
|
|
||||||
|
|
||||||
/******************* Main EKF loop ****************************/
|
|
||||||
while(1) {
|
|
||||||
AhrsPoll();
|
|
||||||
AhrsStatus2Data status;
|
|
||||||
AhrsStatus2Get(&status);
|
|
||||||
status.CPULoad = ((float)running_counts /
|
|
||||||
(float)(idle_counts + running_counts)) * 100;
|
|
||||||
status.IdleTimePerCyle = idle_counts / (TIMER_RATE / 10000);
|
|
||||||
status.RunningTimePerCyle = running_counts / (TIMER_RATE / 10000);
|
|
||||||
status.DroppedUpdates = ekf_too_slow;
|
|
||||||
AhrsStatus2Set(&status);
|
|
||||||
|
|
||||||
// Alive signal
|
|
||||||
if ((total_conversion_blocks % 100) == 0)
|
|
||||||
PIOS_LED_Toggle(LED1);
|
|
||||||
|
|
||||||
#if defined(PIOS_INCLUDE_HMC5843) && defined(PIOS_INCLUDE_I2C)
|
|
||||||
// Get magnetic readings
|
|
||||||
if (PIOS_HMC5843_NewDataAvailable()) {
|
|
||||||
PIOS_HMC5843_ReadMag(mag_data.raw.axis);
|
|
||||||
mag_data.scaled.axis[0] = (mag_data.raw.axis[0] * mag_data.calibration.scale[0]) + mag_data.calibration.bias[0];
|
|
||||||
mag_data.scaled.axis[1] = (mag_data.raw.axis[1] * mag_data.calibration.scale[1]) + mag_data.calibration.bias[1];
|
|
||||||
mag_data.scaled.axis[2] = (mag_data.raw.axis[2] * mag_data.calibration.scale[2]) + mag_data.calibration.bias[2];
|
|
||||||
mag_data.updated = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
// Delay for valid data
|
|
||||||
|
|
||||||
counter_val = timer_count();
|
|
||||||
running_counts = counter_val - last_counter_idle_end;
|
|
||||||
last_counter_idle_start = counter_val;
|
|
||||||
|
|
||||||
while (ahrs_state != AHRS_DATA_READY) ;
|
|
||||||
|
|
||||||
counter_val = timer_count();
|
|
||||||
idle_counts = counter_val - last_counter_idle_start;
|
|
||||||
last_counter_idle_end = counter_val;
|
|
||||||
|
|
||||||
ahrs_state = AHRS_PROCESSING;
|
|
||||||
|
|
||||||
downsample_data();
|
|
||||||
|
|
||||||
/******************** INS ALGORITHM **************************/
|
|
||||||
if (ahrs_algorithm == INSGPS_Algo) {
|
|
||||||
|
|
||||||
// format data for INS algo
|
|
||||||
gyro[0] = gyro_data.filtered.x;
|
|
||||||
gyro[1] = gyro_data.filtered.y;
|
|
||||||
gyro[2] = gyro_data.filtered.z;
|
|
||||||
accel[0] = accel_data.filtered.x,
|
|
||||||
accel[1] = accel_data.filtered.y,
|
|
||||||
accel[2] = accel_data.filtered.z,
|
|
||||||
// Note: The magnetometer driver returns registers X,Y,Z from the chip which are
|
|
||||||
// (left, backward, up). Remapping to (forward, right, down).
|
|
||||||
mag[0] = -mag_data.scaled.axis[1];
|
|
||||||
mag[1] = -mag_data.scaled.axis[0];
|
|
||||||
mag[2] = -mag_data.scaled.axis[2];
|
|
||||||
|
|
||||||
INSStatePrediction(gyro, accel, 1 / (float)EKF_RATE);
|
|
||||||
process_spi_request(); // get message out quickly
|
|
||||||
INSCovariancePrediction(1 / (float)EKF_RATE);
|
|
||||||
|
|
||||||
if (gps_data.updated && gps_data.quality == 1) {
|
|
||||||
// Compute velocity from Heading and groundspeed
|
|
||||||
vel[0] =
|
|
||||||
gps_data.groundspeed *
|
|
||||||
cos(gps_data.heading * M_PI / 180);
|
|
||||||
vel[1] =
|
|
||||||
gps_data.groundspeed *
|
|
||||||
sin(gps_data.heading * M_PI / 180);
|
|
||||||
|
|
||||||
INSSetPosVelVar(0.004);
|
|
||||||
if (gps_data.updated) {
|
|
||||||
//TOOD: add check for altitude updates
|
|
||||||
FullCorrection(mag, gps_data.NED,
|
|
||||||
vel,
|
|
||||||
altitude_data.
|
|
||||||
altitude);
|
|
||||||
gps_data.updated = 0;
|
|
||||||
} else {
|
|
||||||
GpsBaroCorrection(gps_data.NED,
|
|
||||||
vel,
|
|
||||||
altitude_data.
|
|
||||||
altitude);
|
|
||||||
}
|
|
||||||
|
|
||||||
gps_data.updated = false;
|
|
||||||
mag_data.updated = 0;
|
|
||||||
} else if (gps_data.quality != -1
|
|
||||||
&& mag_data.updated == 1) {
|
|
||||||
float mag_var[3] = {mag_data.calibration.variance[1], mag_data.calibration.variance[0], mag_data.calibration.variance[2]};
|
|
||||||
INSSetMagVar(mag_var);
|
|
||||||
MagCorrection(mag); // only trust mags if outdoors
|
|
||||||
mag_data.updated = 0;
|
|
||||||
} else {
|
|
||||||
// Indoors, update with zero position and velocity and high covariance
|
|
||||||
INSSetPosVelVar(0.1);
|
|
||||||
vel[0] = 0;
|
|
||||||
vel[1] = 0;
|
|
||||||
vel[2] = 0;
|
|
||||||
|
|
||||||
if(mag_data.updated == 1) {
|
|
||||||
float mag_var[3] = {10,10,10};
|
|
||||||
INSSetMagVar(mag_var);
|
|
||||||
MagVelBaroCorrection(mag,vel,altitude_data.altitude); // only trust mags if outdoors
|
|
||||||
mag_data.updated = 0;
|
|
||||||
} else {
|
|
||||||
VelBaroCorrection(vel, altitude_data.altitude);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
attitude_data.quaternion.q1 = Nav.q[0];
|
|
||||||
attitude_data.quaternion.q2 = Nav.q[1];
|
|
||||||
attitude_data.quaternion.q3 = Nav.q[2];
|
|
||||||
attitude_data.quaternion.q4 = Nav.q[3];
|
|
||||||
} else if (ahrs_algorithm == SIMPLE_Algo) {
|
|
||||||
float q[4];
|
|
||||||
float rpy[3];
|
|
||||||
/***************** SIMPLE ATTITUDE FROM NORTH AND ACCEL ************/
|
|
||||||
/* Very simple computation of the heading and attitude from accel. */
|
|
||||||
rpy[2] =
|
|
||||||
atan2((mag_data.raw.axis[0]),
|
|
||||||
(-1 * mag_data.raw.axis[1])) * 180 /
|
|
||||||
M_PI;
|
|
||||||
rpy[1] =
|
|
||||||
atan2(accel_data.filtered.x,
|
|
||||||
accel_data.filtered.z) * 180 / M_PI;
|
|
||||||
rpy[0] =
|
|
||||||
atan2(accel_data.filtered.y,
|
|
||||||
accel_data.filtered.z) * 180 / M_PI;
|
|
||||||
|
|
||||||
RPY2Quaternion(rpy, q);
|
|
||||||
attitude_data.quaternion.q1 = q[0];
|
|
||||||
attitude_data.quaternion.q2 = q[1];
|
|
||||||
attitude_data.quaternion.q3 = q[2];
|
|
||||||
attitude_data.quaternion.q4 = q[3];
|
|
||||||
process_spi_request();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ahrs_state = AHRS_IDLE;
|
|
||||||
|
|
||||||
#ifdef DUMP_FRIENDLY
|
|
||||||
PIOS_COM_SendFormattedStringNonBlocking(PIOS_COM_AUX, "b: %d\r\n",
|
|
||||||
total_conversion_blocks);
|
|
||||||
PIOS_COM_SendFormattedStringNonBlocking(PIOS_COM_AUX,"a: %d %d %d\r\n",
|
|
||||||
(int16_t) (accel_data.filtered.x * 1000),
|
|
||||||
(int16_t) (accel_data.filtered.y * 1000),
|
|
||||||
(int16_t) (accel_data.filtered.z * 1000));
|
|
||||||
PIOS_COM_SendFormattedStringNonBlocking(PIOS_COM_AUX, "g: %d %d %d\r\n",
|
|
||||||
(int16_t) (gyro_data.filtered.x * 1000),
|
|
||||||
(int16_t) (gyro_data.filtered.y * 1000),
|
|
||||||
(int16_t) (gyro_data.filtered.z * 1000));
|
|
||||||
PIOS_COM_SendFormattedStringNonBlocking(PIOS_COM_AUX,"m: %d %d %d\r\n",
|
|
||||||
mag_data.raw.axis[0],
|
|
||||||
mag_data.raw.axis[1],
|
|
||||||
mag_data.raw.axis[2]);
|
|
||||||
PIOS_COM_SendFormattedStringNonBlocking(PIOS_COM_AUX,
|
|
||||||
"q: %d %d %d %d\r\n",
|
|
||||||
(int16_t) (Nav.q[0] * 1000),
|
|
||||||
(int16_t) (Nav.q[1] * 1000),
|
|
||||||
(int16_t) (Nav.q[2] * 1000),
|
|
||||||
(int16_t) (Nav.q[3] * 1000));
|
|
||||||
#endif
|
|
||||||
#ifdef DUMP_EKF
|
|
||||||
uint8_t framing[16] =
|
|
||||||
{ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
|
|
||||||
0 };
|
|
||||||
extern float F[NUMX][NUMX], G[NUMX][NUMW], H[NUMV][NUMX]; // linearized system matrices
|
|
||||||
extern float P[NUMX][NUMX], X[NUMX]; // covariance matrix and state vector
|
|
||||||
extern float Q[NUMW], R[NUMV]; // input noise and measurement noise variances
|
|
||||||
extern float K[NUMX][NUMV]; // feedback gain matrix
|
|
||||||
|
|
||||||
// Dump raw buffer
|
|
||||||
int8_t result;
|
|
||||||
result = PIOS_COM_SendBuffer(PIOS_COM_AUX, &framing[0], 16); // framing header
|
|
||||||
result += PIOS_COM_SendBuffer(PIOS_COM_AUX, (uint8_t *) & total_conversion_blocks, sizeof(total_conversion_blocks)); // dump block number
|
|
||||||
result +=
|
|
||||||
PIOS_COM_SendBuffer(PIOS_COM_AUX,
|
|
||||||
(uint8_t *) & mag_data,
|
|
||||||
sizeof(mag_data));
|
|
||||||
result +=
|
|
||||||
PIOS_COM_SendBuffer(PIOS_COM_AUX,
|
|
||||||
(uint8_t *) & gps_data,
|
|
||||||
sizeof(gps_data));
|
|
||||||
result +=
|
|
||||||
PIOS_COM_SendBuffer(PIOS_COM_AUX,
|
|
||||||
(uint8_t *) & accel_data,
|
|
||||||
sizeof(accel_data));
|
|
||||||
result +=
|
|
||||||
PIOS_COM_SendBuffer(PIOS_COM_AUX,
|
|
||||||
(uint8_t *) & gyro_data,
|
|
||||||
sizeof(gyro_data));
|
|
||||||
result +=
|
|
||||||
PIOS_COM_SendBuffer(PIOS_COM_AUX, (uint8_t *) & Q,
|
|
||||||
sizeof(float) * NUMX * NUMX);
|
|
||||||
result +=
|
|
||||||
PIOS_COM_SendBuffer(PIOS_COM_AUX, (uint8_t *) & K,
|
|
||||||
sizeof(float) * NUMX * NUMV);
|
|
||||||
result +=
|
|
||||||
PIOS_COM_SendBuffer(PIOS_COM_AUX, (uint8_t *) & X,
|
|
||||||
sizeof(float) * NUMX * NUMX);
|
|
||||||
|
|
||||||
if (result == 0)
|
|
||||||
PIOS_LED_Off(LED1);
|
|
||||||
else {
|
|
||||||
PIOS_LED_On(LED1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Downsample the analog data
|
|
||||||
* @return none
|
|
||||||
*
|
|
||||||
* Tried to make as much of the filtering fixed point when possible. Need to account
|
|
||||||
* for offset for each sample before the multiplication if filter not a boxcar. Could
|
|
||||||
* precompute fixed offset as sum[fir_coeffs[i]] * ACCEL_OFFSET. Puts data into global
|
|
||||||
* data structures @ref accel_data and @ref gyro_data.
|
|
||||||
*
|
|
||||||
* The accel_data values are converted into a coordinate system where X is forwards along
|
|
||||||
* the fuselage, Y is along right the wing, and Z is down.
|
|
||||||
*/
|
|
||||||
void downsample_data()
|
|
||||||
{
|
|
||||||
uint16_t i;
|
|
||||||
|
|
||||||
// Get the Y data. Third byte in. Convert to m/s
|
|
||||||
accel_data.filtered.y = 0;
|
|
||||||
for (i = 0; i < adc_oversampling; i++)
|
|
||||||
accel_data.filtered.y += valid_data_buffer[0 + i * PIOS_ADC_NUM_PINS] * fir_coeffs[i];
|
|
||||||
accel_data.filtered.y /= (float) fir_coeffs[adc_oversampling];
|
|
||||||
accel_data.filtered.y = (accel_data.filtered.y * accel_data.calibration.scale[1]) + accel_data.calibration.bias[1];
|
|
||||||
|
|
||||||
// Get the X data which projects forward/backwards. Fifth byte in. Convert to m/s
|
|
||||||
accel_data.filtered.x = 0;
|
|
||||||
for (i = 0; i < adc_oversampling; i++)
|
|
||||||
accel_data.filtered.x += valid_data_buffer[2 + i * PIOS_ADC_NUM_PINS] * fir_coeffs[i];
|
|
||||||
accel_data.filtered.x /= (float) fir_coeffs[adc_oversampling];
|
|
||||||
accel_data.filtered.x = (accel_data.filtered.x * accel_data.calibration.scale[0]) + accel_data.calibration.bias[0];
|
|
||||||
|
|
||||||
// Get the Z data. Third byte in. Convert to m/s
|
|
||||||
accel_data.filtered.z = 0;
|
|
||||||
for (i = 0; i < adc_oversampling; i++)
|
|
||||||
accel_data.filtered.z += valid_data_buffer[4 + i * PIOS_ADC_NUM_PINS] * fir_coeffs[i];
|
|
||||||
accel_data.filtered.z /= (float) fir_coeffs[adc_oversampling];
|
|
||||||
accel_data.filtered.z = (accel_data.filtered.z * accel_data.calibration.scale[2]) + accel_data.calibration.bias[2];
|
|
||||||
|
|
||||||
// Get the X gyro data. Seventh byte in. Convert to deg/s.
|
|
||||||
gyro_data.filtered.x = 0;
|
|
||||||
for (i = 0; i < adc_oversampling; i++)
|
|
||||||
gyro_data.filtered.x += valid_data_buffer[1 + i * PIOS_ADC_NUM_PINS] * fir_coeffs[i];
|
|
||||||
gyro_data.filtered.x /= fir_coeffs[adc_oversampling];
|
|
||||||
gyro_data.filtered.x = (gyro_data.filtered.x * gyro_data.calibration.scale[0]) + gyro_data.calibration.bias[0];
|
|
||||||
|
|
||||||
// Get the Y gyro data. Second byte in. Convert to deg/s.
|
|
||||||
gyro_data.filtered.y = 0;
|
|
||||||
for (i = 0; i < adc_oversampling; i++)
|
|
||||||
gyro_data.filtered.y += valid_data_buffer[3 + i * PIOS_ADC_NUM_PINS] * fir_coeffs[i];
|
|
||||||
gyro_data.filtered.y /= fir_coeffs[adc_oversampling];
|
|
||||||
gyro_data.filtered.y = (gyro_data.filtered.y * gyro_data.calibration.scale[1]) + gyro_data.calibration.bias[1];
|
|
||||||
|
|
||||||
// Get the Z gyro data. Fifth byte in. Convert to deg/s.
|
|
||||||
gyro_data.filtered.z = 0;
|
|
||||||
for (i = 0; i < adc_oversampling; i++)
|
|
||||||
gyro_data.filtered.z += valid_data_buffer[5 + i * PIOS_ADC_NUM_PINS] * fir_coeffs[i];
|
|
||||||
gyro_data.filtered.z /= fir_coeffs[adc_oversampling];
|
|
||||||
gyro_data.filtered.z = (gyro_data.filtered.z * gyro_data.calibration.scale[2]) + gyro_data.calibration.bias[2];
|
|
||||||
|
|
||||||
AttitudeRawData raw;
|
|
||||||
|
|
||||||
raw.gyros[0] = valid_data_buffer[1];
|
|
||||||
raw.gyros[1] = valid_data_buffer[3];
|
|
||||||
raw.gyros[2] = valid_data_buffer[5];
|
|
||||||
|
|
||||||
raw.gyros_filtered[0] = gyro_data.filtered.x;
|
|
||||||
raw.gyros_filtered[1] = gyro_data.filtered.y;
|
|
||||||
raw.gyros_filtered[2] = gyro_data.filtered.z;
|
|
||||||
|
|
||||||
raw.accels[0] = valid_data_buffer[2];
|
|
||||||
raw.accels[1] = valid_data_buffer[0];
|
|
||||||
raw.accels[2] = valid_data_buffer[4];
|
|
||||||
|
|
||||||
raw.accels_filtered[0] = accel_data.filtered.x;
|
|
||||||
raw.accels_filtered[1] = accel_data.filtered.y;
|
|
||||||
raw.accels_filtered[2] = accel_data.filtered.z;
|
|
||||||
|
|
||||||
raw.magnetometers[0] = mag_data.scaled.axis[0];
|
|
||||||
raw.magnetometers[1] = mag_data.scaled.axis[1];
|
|
||||||
raw.magnetometers[2] = mag_data.scaled.axis[2];
|
|
||||||
|
|
||||||
AttitudeRawSet(&raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Assumes board is not moving computes biases and variances of sensors
|
|
||||||
* @returns None
|
|
||||||
*
|
|
||||||
* All data is stored in global structures. This function should be called from OP when
|
|
||||||
* aircraft is in stable state and then the data stored to SD card.
|
|
||||||
*
|
|
||||||
* After this function the bias for each sensor will be the mean value. This doesn't make
|
|
||||||
* sense for the z accel so make sure 6 point calibration is also run and those values set
|
|
||||||
* after these read.
|
|
||||||
*/
|
|
||||||
#define NBIAS 100
|
|
||||||
#define NVAR 500
|
|
||||||
void calibrate_sensors()
|
|
||||||
{
|
|
||||||
int i,j;
|
|
||||||
float accel_bias[3] = {0, 0, 0};
|
|
||||||
float gyro_bias[3] = {0, 0, 0};
|
|
||||||
float mag_bias[3] = {0, 0, 0};
|
|
||||||
|
|
||||||
|
|
||||||
for (i = 0, j = 0; i < NBIAS; i++) {
|
|
||||||
while (ahrs_state != AHRS_DATA_READY) ;
|
|
||||||
ahrs_state = AHRS_PROCESSING;
|
|
||||||
downsample_data();
|
|
||||||
gyro_bias[0] += gyro_data.filtered.x / NBIAS;
|
|
||||||
gyro_bias[1] += gyro_data.filtered.y / NBIAS;
|
|
||||||
gyro_bias[2] += gyro_data.filtered.z / NBIAS;
|
|
||||||
accel_bias[0] += accel_data.filtered.x / NBIAS;
|
|
||||||
accel_bias[1] += accel_data.filtered.y / NBIAS;
|
|
||||||
accel_bias[2] += accel_data.filtered.z / NBIAS;
|
|
||||||
ahrs_state = AHRS_IDLE;
|
|
||||||
|
|
||||||
#if defined(PIOS_INCLUDE_HMC5843) && defined(PIOS_INCLUDE_I2C)
|
|
||||||
if(PIOS_HMC5843_NewDataAvailable()) {
|
|
||||||
j ++;
|
|
||||||
PIOS_HMC5843_ReadMag(mag_data.raw.axis);
|
|
||||||
mag_data.scaled.axis[0] = (mag_data.raw.axis[0] * mag_data.calibration.scale[0]) + mag_data.calibration.bias[0];
|
|
||||||
mag_data.scaled.axis[1] = (mag_data.raw.axis[1] * mag_data.calibration.scale[1]) + mag_data.calibration.bias[1];
|
|
||||||
mag_data.scaled.axis[2] = (mag_data.raw.axis[2] * mag_data.calibration.scale[2]) + mag_data.calibration.bias[2];
|
|
||||||
mag_bias[0] += mag_data.scaled.axis[0];
|
|
||||||
mag_bias[1] += mag_data.scaled.axis[1];
|
|
||||||
mag_bias[2] += mag_data.scaled.axis[2];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
mag_bias[0] /= j;
|
|
||||||
mag_bias[1] /= j;
|
|
||||||
mag_bias[2] /= j;
|
|
||||||
|
|
||||||
gyro_data.calibration.variance[0] = 0;
|
|
||||||
gyro_data.calibration.variance[1] = 0;
|
|
||||||
gyro_data.calibration.variance[2] = 0;
|
|
||||||
mag_data.calibration.variance[0] = 0;
|
|
||||||
mag_data.calibration.variance[1] = 0;
|
|
||||||
mag_data.calibration.variance[2] = 0;
|
|
||||||
accel_data.calibration.variance[0] = 0;
|
|
||||||
accel_data.calibration.variance[1] = 0;
|
|
||||||
accel_data.calibration.variance[2] = 0;
|
|
||||||
|
|
||||||
for (i = 0, j = 0; j < NVAR; j++) {
|
|
||||||
while (ahrs_state != AHRS_DATA_READY) ;
|
|
||||||
ahrs_state = AHRS_PROCESSING;
|
|
||||||
downsample_data();
|
|
||||||
gyro_data.calibration.variance[0] += pow(gyro_data.filtered.x-gyro_bias[0],2) / NVAR;
|
|
||||||
gyro_data.calibration.variance[1] += pow(gyro_data.filtered.y-gyro_bias[1],2) / NVAR;
|
|
||||||
gyro_data.calibration.variance[2] += pow(gyro_data.filtered.z-gyro_bias[2],2) / NVAR;
|
|
||||||
accel_data.calibration.variance[0] += pow(accel_data.filtered.x-accel_bias[0],2) / NVAR;
|
|
||||||
accel_data.calibration.variance[1] += pow(accel_data.filtered.y-accel_bias[1],2) / NVAR;
|
|
||||||
accel_data.calibration.variance[2] += pow(accel_data.filtered.z-accel_bias[2],2) / NVAR;
|
|
||||||
ahrs_state = AHRS_IDLE;
|
|
||||||
#if defined(PIOS_INCLUDE_HMC5843) && defined(PIOS_INCLUDE_I2C)
|
|
||||||
if(PIOS_HMC5843_NewDataAvailable()) {
|
|
||||||
j ++;
|
|
||||||
PIOS_HMC5843_ReadMag(mag_data.raw.axis);
|
|
||||||
mag_data.scaled.axis[0] = (mag_data.raw.axis[0] * mag_data.calibration.scale[0]) + mag_data.calibration.bias[0];
|
|
||||||
mag_data.scaled.axis[1] = (mag_data.raw.axis[1] * mag_data.calibration.scale[1]) + mag_data.calibration.bias[1];
|
|
||||||
mag_data.scaled.axis[2] = (mag_data.raw.axis[2] * mag_data.calibration.scale[2]) + mag_data.calibration.bias[2];
|
|
||||||
mag_data.calibration.variance[0] += pow(mag_data.scaled.axis[0]-mag_bias[0],2);
|
|
||||||
mag_data.calibration.variance[1] += pow(mag_data.scaled.axis[1]-mag_bias[1],2);
|
|
||||||
mag_data.calibration.variance[2] += pow(mag_data.scaled.axis[2]-mag_bias[2],2);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
mag_data.calibration.variance[0] /= j;
|
|
||||||
mag_data.calibration.variance[1] /= j;
|
|
||||||
mag_data.calibration.variance[2] /= j;
|
|
||||||
|
|
||||||
gyro_data.calibration.bias[0] -= gyro_bias[0];
|
|
||||||
gyro_data.calibration.bias[1] -= gyro_bias[1];
|
|
||||||
gyro_data.calibration.bias[2] -= gyro_bias[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Populate fields with initial values
|
|
||||||
*/
|
|
||||||
void reset_values() {
|
|
||||||
accel_data.calibration.scale[0] = 0.012;
|
|
||||||
accel_data.calibration.scale[1] = 0.012;
|
|
||||||
accel_data.calibration.scale[2] = -0.012;
|
|
||||||
accel_data.calibration.bias[0] = 24;
|
|
||||||
accel_data.calibration.bias[1] = 24;
|
|
||||||
accel_data.calibration.bias[2] = -24;
|
|
||||||
accel_data.calibration.variance[0] = 1e-4;
|
|
||||||
accel_data.calibration.variance[1] = 1e-4;
|
|
||||||
accel_data.calibration.variance[2] = 1e-4;
|
|
||||||
gyro_data.calibration.scale[0] = -0.014;
|
|
||||||
gyro_data.calibration.scale[1] = 0.014;
|
|
||||||
gyro_data.calibration.scale[2] = -0.014;
|
|
||||||
gyro_data.calibration.bias[0] = -24;
|
|
||||||
gyro_data.calibration.bias[1] = -24;
|
|
||||||
gyro_data.calibration.bias[2] = -24;
|
|
||||||
gyro_data.calibration.variance[0] = 1;
|
|
||||||
gyro_data.calibration.variance[1] = 1;
|
|
||||||
gyro_data.calibration.variance[2] = 1;
|
|
||||||
mag_data.calibration.scale[0] = 1;
|
|
||||||
mag_data.calibration.scale[1] = 1;
|
|
||||||
mag_data.calibration.scale[2] = 1;
|
|
||||||
mag_data.calibration.bias[0] = 0;
|
|
||||||
mag_data.calibration.bias[1] = 0;
|
|
||||||
mag_data.calibration.bias[2] = 0;
|
|
||||||
mag_data.calibration.variance[0] = 1;
|
|
||||||
mag_data.calibration.variance[1] = 1;
|
|
||||||
mag_data.calibration.variance[2] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void process_spi_request(void)
|
|
||||||
{
|
|
||||||
AttitudeActualData attitude;
|
|
||||||
attitude.q1 = attitude_data.quaternion.q1;
|
|
||||||
attitude.q2 = attitude_data.quaternion.q2;
|
|
||||||
attitude.q3 = attitude_data.quaternion.q3;
|
|
||||||
attitude.q4 = attitude_data.quaternion.q4;
|
|
||||||
float rpy[3];
|
|
||||||
Quaternion2RPY(&attitude_data.quaternion.q1, rpy);
|
|
||||||
attitude.Roll = rpy[0];
|
|
||||||
attitude.Pitch = rpy[1];
|
|
||||||
attitude.Yaw = rpy[2];
|
|
||||||
AttitudeActualSet(&attitude);
|
|
||||||
}
|
|
||||||
|
|
||||||
void send_calibration(void)
|
|
||||||
{
|
|
||||||
AHRSCalibrationData cal;
|
|
||||||
AHRSCalibrationGet(&cal);
|
|
||||||
for(int ct=0; ct<3; ct++)
|
|
||||||
{
|
|
||||||
cal.accel_var[ct] = accel_data.calibration.variance[ct];
|
|
||||||
cal.gyro_bias[ct] = gyro_data.calibration.bias[ct];
|
|
||||||
cal.gyro_var[ct] = gyro_data.calibration.variance[ct];
|
|
||||||
cal.mag_var[ct] = mag_data.calibration.variance[ct];
|
|
||||||
}
|
|
||||||
cal.measure_var = AHRSCALIBRATION_MEASURE_VAR_SET;
|
|
||||||
AHRSCalibrationSet(&cal);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief AHRS calibration callback
|
|
||||||
*
|
|
||||||
* Called when the OP board sets the calibration
|
|
||||||
*/
|
|
||||||
void calibration_callback(AhrsObjHandle obj)
|
|
||||||
{
|
|
||||||
AHRSCalibrationData cal;
|
|
||||||
AHRSCalibrationGet(&cal);
|
|
||||||
if(cal.measure_var == AHRSCALIBRATION_MEASURE_VAR_SET){
|
|
||||||
for(int ct=0; ct<3; ct++)
|
|
||||||
{
|
|
||||||
accel_data.calibration.scale[ct] = cal.accel_scale[ct];
|
|
||||||
accel_data.calibration.bias[ct] = cal.accel_bias[ct];
|
|
||||||
accel_data.calibration.variance[ct] = cal.accel_var[ct];
|
|
||||||
gyro_data.calibration.scale[ct] = cal.gyro_scale[ct];
|
|
||||||
gyro_data.calibration.bias[ct] = cal.gyro_bias[ct];
|
|
||||||
gyro_data.calibration.variance[ct] = cal.gyro_var[ct];
|
|
||||||
mag_data.calibration.bias[ct] = cal.mag_bias[ct];
|
|
||||||
mag_data.calibration.scale[ct] = cal.mag_scale[ct];
|
|
||||||
mag_data.calibration.variance[ct] = cal.mag_var[ct];
|
|
||||||
}
|
|
||||||
}else if(cal.measure_var == AHRSCALIBRATION_MEASURE_VAR_MEASURE){
|
|
||||||
calibrate_sensors();
|
|
||||||
AHRSCalibrationData cal;
|
|
||||||
AHRSCalibrationGet(&cal);
|
|
||||||
cal.measure_var = AHRSCALIBRATION_MEASURE_VAR_SET;
|
|
||||||
AHRSCalibrationSet(&cal);
|
|
||||||
|
|
||||||
}else if(cal.measure_var == AHRSCALIBRATION_MEASURE_VAR_ECHO){
|
|
||||||
send_calibration();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void gps_callback(AhrsObjHandle obj)
|
|
||||||
{
|
|
||||||
GPSPositionData pos;
|
|
||||||
GPSPositionGet(&pos);
|
|
||||||
HomeLocationData home;
|
|
||||||
HomeLocationGet(&home);
|
|
||||||
|
|
||||||
if(home.Set == HOMELOCATION_SET_FALSE || home.Indoor == HOMELOCATION_INDOOR_TRUE) {
|
|
||||||
gps_data.NED[0] = 0;
|
|
||||||
gps_data.NED[1] = 0;
|
|
||||||
gps_data.NED[2] = 0;
|
|
||||||
gps_data.groundspeed = 0;
|
|
||||||
gps_data.heading = 0;
|
|
||||||
gps_data.quality = -1; // indicates indoor mode, high variance zeros update
|
|
||||||
gps_data.updated = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pos.Status != GPSPOSITION_STATUS_FIX3D) //FIXME: Will this work? the old ahrs_comms does it differently.
|
|
||||||
{
|
|
||||||
gps_data.quality = 0;
|
|
||||||
gps_data.updated = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
double LLA[3] = {(double) pos.Latitude / 1e7, (double) pos.Longitude / 1e7, (double) (pos.GeoidSeparation + pos.Altitude)};
|
|
||||||
// convert from cm back to meters
|
|
||||||
double ECEF[3] = {(double) (home.ECEF[0] / 100), (double) (home.ECEF[1] / 100), (double) (home.ECEF[2] / 100)};
|
|
||||||
LLA2Base(LLA, ECEF, (float (*)[3]) home.RNE, gps_data.NED);
|
|
||||||
|
|
||||||
gps_data.heading = pos.Heading;
|
|
||||||
gps_data.groundspeed = pos.Groundspeed;
|
|
||||||
gps_data.quality = 1;
|
|
||||||
gps_data.updated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void altitude_callback(AhrsObjHandle obj)
|
|
||||||
{
|
|
||||||
BaroAltitudeData alt;
|
|
||||||
BaroAltitudeGet(&alt);
|
|
||||||
altitude_data.altitude = alt.Altitude;
|
|
||||||
altitude_data.updated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void settings_callback(AhrsObjHandle obj)
|
|
||||||
{
|
|
||||||
AHRSSettingsData settings;
|
|
||||||
AHRSSettingsGet(&settings);
|
|
||||||
|
|
||||||
if(settings.Algorithm == AHRSSETTINGS_ALGORITHM_INSGPS)
|
|
||||||
{
|
|
||||||
ahrs_algorithm = INSGPS_Algo;
|
|
||||||
}else
|
|
||||||
{
|
|
||||||
ahrs_algorithm = SIMPLE_Algo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
@ -5,7 +5,7 @@ static AttitudeRawData AttitudeRaw;
|
|||||||
static AttitudeActualData AttitudeActual;
|
static AttitudeActualData AttitudeActual;
|
||||||
static AHRSCalibrationData AHRSCalibration;
|
static AHRSCalibrationData AHRSCalibration;
|
||||||
static AttitudeSettingsData AttitudeSettings;
|
static AttitudeSettingsData AttitudeSettings;
|
||||||
static AhrsStatus2Data AhrsStatus2;
|
static AhrsStatusData AhrsStatus;
|
||||||
static BaroAltitudeData BaroAltitude;
|
static BaroAltitudeData BaroAltitude;
|
||||||
static GPSPositionData GPSPosition;
|
static GPSPositionData GPSPosition;
|
||||||
static PositionActualData PositionActual;
|
static PositionActualData PositionActual;
|
||||||
@ -28,7 +28,7 @@ CREATEHANDLE( 0, AttitudeRaw );
|
|||||||
CREATEHANDLE( 1, AttitudeActual );
|
CREATEHANDLE( 1, AttitudeActual );
|
||||||
CREATEHANDLE( 2, AHRSCalibration );
|
CREATEHANDLE( 2, AHRSCalibration );
|
||||||
CREATEHANDLE( 3, AttitudeSettings );
|
CREATEHANDLE( 3, AttitudeSettings );
|
||||||
CREATEHANDLE( 4, AhrsStatus2 );
|
CREATEHANDLE( 4, AhrsStatus );
|
||||||
CREATEHANDLE( 5, BaroAltitude );
|
CREATEHANDLE( 5, BaroAltitude );
|
||||||
CREATEHANDLE( 6, GPSPosition );
|
CREATEHANDLE( 6, GPSPosition );
|
||||||
CREATEHANDLE( 7, PositionActual );
|
CREATEHANDLE( 7, PositionActual );
|
||||||
@ -70,7 +70,7 @@ void AhrsInitHandles( void )
|
|||||||
ADDHANDLE( idx++, AttitudeActual );
|
ADDHANDLE( idx++, AttitudeActual );
|
||||||
ADDHANDLE( idx++, AHRSCalibration );
|
ADDHANDLE( idx++, AHRSCalibration );
|
||||||
ADDHANDLE( idx++, AttitudeSettings );
|
ADDHANDLE( idx++, AttitudeSettings );
|
||||||
ADDHANDLE( idx++, AhrsStatus2 );
|
ADDHANDLE( idx++, AhrsStatus );
|
||||||
ADDHANDLE( idx++, BaroAltitude );
|
ADDHANDLE( idx++, BaroAltitude );
|
||||||
ADDHANDLE( idx++, GPSPosition );
|
ADDHANDLE( idx++, GPSPosition );
|
||||||
ADDHANDLE( idx++, PositionActual );
|
ADDHANDLE( idx++, PositionActual );
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include "attitudeactual.h"
|
#include "attitudeactual.h"
|
||||||
#include "attituderaw.h"
|
#include "attituderaw.h"
|
||||||
#include "attitudesettings.h"
|
#include "attitudesettings.h"
|
||||||
#include "ahrsstatus2.h"
|
#include "ahrsstatus.h"
|
||||||
#include "baroaltitude.h"
|
#include "baroaltitude.h"
|
||||||
#include "gpsposition.h"
|
#include "gpsposition.h"
|
||||||
#include "positionactual.h"
|
#include "positionactual.h"
|
||||||
@ -20,7 +20,7 @@ typedef union {
|
|||||||
AttitudeActualData AttitudeActual;
|
AttitudeActualData AttitudeActual;
|
||||||
AHRSCalibrationData AHRSCalibration;
|
AHRSCalibrationData AHRSCalibration;
|
||||||
AttitudeSettingsData AttitudeSettings;
|
AttitudeSettingsData AttitudeSettings;
|
||||||
AhrsStatus2Data AhrsStatus2;
|
AhrsStatusData AhrsStatus;
|
||||||
BaroAltitudeData BaroAltitude;
|
BaroAltitudeData BaroAltitude;
|
||||||
GPSPositionData GPSPosition;
|
GPSPositionData GPSPosition;
|
||||||
PositionActualData PositionActual;
|
PositionActualData PositionActual;
|
||||||
|
@ -217,10 +217,11 @@ SRC += $(PIOSSTM32F10X)/pios_usb_hid_pwr.c
|
|||||||
SRC += $(PIOSCOMMON)/pios_sdcard.c
|
SRC += $(PIOSCOMMON)/pios_sdcard.c
|
||||||
SRC += $(PIOSCOMMON)/pios_com.c
|
SRC += $(PIOSCOMMON)/pios_com.c
|
||||||
SRC += $(PIOSCOMMON)/pios_bmp085.c
|
SRC += $(PIOSCOMMON)/pios_bmp085.c
|
||||||
SRC += $(PIOSCOMMON)/pios_opahrs.c
|
#SRC += $(PIOSCOMMON)/pios_opahrs.c
|
||||||
SRC += $(PIOSCOMMON)/pios_opahrs_proto.c
|
#SRC += $(PIOSCOMMON)/pios_opahrs_proto.c
|
||||||
SRC += $(PIOSCOMMON)/printf-stdarg.c
|
SRC += $(PIOSCOMMON)/printf-stdarg.c
|
||||||
|
SRC += $(FLIGHTLIB)/ahrs_spi_comm.c
|
||||||
|
SRC += $(FLIGHTLIB)/ahrs_comm_objects.c
|
||||||
## Libraries for flight calculations
|
## Libraries for flight calculations
|
||||||
SRC += $(FLIGHTLIB)/buffer.c
|
SRC += $(FLIGHTLIB)/buffer.c
|
||||||
SRC += $(FLIGHTLIB)/WorldMagModel.c
|
SRC += $(FLIGHTLIB)/WorldMagModel.c
|
||||||
|
@ -31,11 +31,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Input object: AttitudeSettings
|
* Input objects: As defined in PiOS/inc/pios_ahrs_comms.h
|
||||||
* Output object: AttitudeActual
|
* Output objects: As defined in PiOS/inc/pios_ahrs_comms.h
|
||||||
*
|
*
|
||||||
* This module will periodically update the value of latest attitude solution
|
* This module will periodically update the values of latest attitude solution
|
||||||
* that is available from the AHRS.
|
* and other objects that are transferred to and from the AHRS
|
||||||
* The module settings can configure how often AHRS is polled for a new solution.
|
* The module settings can configure how often AHRS is polled for a new solution.
|
||||||
*
|
*
|
||||||
* The module executes in its own thread.
|
* The module executes in its own thread.
|
||||||
@ -51,26 +51,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ahrs_comms.h"
|
#include "ahrs_comms.h"
|
||||||
#include "attitudeactual.h"
|
|
||||||
#include "ahrssettings.h"
|
|
||||||
#include "attituderaw.h"
|
|
||||||
#include "attitudesettings.h"
|
|
||||||
#include "ahrsstatus.h"
|
|
||||||
#include "alarms.h"
|
|
||||||
#include "baroaltitude.h"
|
|
||||||
#include "stdbool.h"
|
|
||||||
#include "gpsposition.h"
|
|
||||||
#include "positionactual.h"
|
|
||||||
#include "velocityactual.h"
|
|
||||||
#include "homelocation.h"
|
|
||||||
#include "ahrscalibration.h"
|
|
||||||
#include "CoordinateConversions.h"
|
|
||||||
|
|
||||||
#include "pios_opahrs.h" // library for OpenPilot AHRS access functions
|
#include "ahrs_spi_comm.h"
|
||||||
#include "pios_opahrs_proto.h"
|
|
||||||
|
|
||||||
// Private constants
|
// Private constants
|
||||||
#define STACK_SIZE 450
|
#define STACK_SIZE 1400
|
||||||
#define TASK_PRIORITY (tskIDLE_PRIORITY+4)
|
#define TASK_PRIORITY (tskIDLE_PRIORITY+4)
|
||||||
|
|
||||||
// Private types
|
// Private types
|
||||||
@ -78,52 +63,10 @@
|
|||||||
// Private variables
|
// Private variables
|
||||||
static xTaskHandle taskHandle;
|
static xTaskHandle taskHandle;
|
||||||
|
|
||||||
|
|
||||||
// Private functions
|
// Private functions
|
||||||
static void ahrscommsTask(void *parameters);
|
static void ahrscommsTask(void* parameters);
|
||||||
static void load_baro_altitude(struct opahrs_msg_v1_req_update *update);
|
|
||||||
static void load_gps_position(struct opahrs_msg_v1_req_update *update);
|
|
||||||
static void load_magnetic_north(struct opahrs_msg_v1_req_north *north);
|
|
||||||
static void load_calibration(struct opahrs_msg_v1_req_calibration *calibration);
|
|
||||||
static void update_attitude_raw(struct opahrs_msg_v1_rsp_attituderaw *attituderaw);
|
|
||||||
static void update_ahrs_status(struct opahrs_msg_v1_rsp_serial *serial);
|
|
||||||
static void update_calibration(struct opahrs_msg_v1_rsp_calibration *calibration);
|
|
||||||
static void process_update(struct opahrs_msg_v1_rsp_update *update); // main information parser
|
|
||||||
|
|
||||||
static bool AHRSSettingsIsUpdatedFlag = false;
|
|
||||||
static void AHRSSettingsUpdatedCb(UAVObjEvent * ev)
|
|
||||||
{
|
|
||||||
AHRSSettingsIsUpdatedFlag = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool BaroAltitudeIsUpdatedFlag = false;
|
|
||||||
static void BaroAltitudeUpdatedCb(UAVObjEvent * ev)
|
|
||||||
{
|
|
||||||
BaroAltitudeIsUpdatedFlag = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GPSPositionIsUpdatedFlag = false;
|
|
||||||
static void GPSPositionUpdatedCb(UAVObjEvent * ev)
|
|
||||||
{
|
|
||||||
GPSPositionIsUpdatedFlag = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool HomeLocationIsUpdatedFlag = false;
|
|
||||||
static void HomeLocationUpdatedCb(UAVObjEvent * ev)
|
|
||||||
{
|
|
||||||
HomeLocationIsUpdatedFlag = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool AHRSCalibrationIsUpdatedFlag = false;
|
|
||||||
static bool AHRSCalibrationIsLocallyUpdateFlag = false;
|
|
||||||
static void AHRSCalibrationUpdatedCb(UAVObjEvent * ev)
|
|
||||||
{
|
|
||||||
if (AHRSCalibrationIsLocallyUpdateFlag == true)
|
|
||||||
AHRSCalibrationIsLocallyUpdateFlag = false;
|
|
||||||
else
|
|
||||||
AHRSCalibrationIsUpdatedFlag = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t GPSGoodUpdates;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise the module, called on startup
|
* Initialise the module, called on startup
|
||||||
@ -131,438 +74,67 @@ static uint32_t GPSGoodUpdates;
|
|||||||
*/
|
*/
|
||||||
int32_t AHRSCommsInitialize(void)
|
int32_t AHRSCommsInitialize(void)
|
||||||
{
|
{
|
||||||
AHRSSettingsConnectCallback(AHRSSettingsUpdatedCb);
|
AhrsInitComms();
|
||||||
BaroAltitudeConnectCallback(BaroAltitudeUpdatedCb);
|
|
||||||
GPSPositionConnectCallback(GPSPositionUpdatedCb);
|
|
||||||
HomeLocationConnectCallback(HomeLocationUpdatedCb);
|
|
||||||
AHRSCalibrationConnectCallback(AHRSCalibrationUpdatedCb);
|
|
||||||
|
|
||||||
PIOS_OPAHRS_Init();
|
|
||||||
|
|
||||||
// Start main task
|
// Start main task
|
||||||
xTaskCreate(ahrscommsTask, (signed char *)"AHRSComms", STACK_SIZE, NULL, TASK_PRIORITY, &taskHandle);
|
xTaskCreate(ahrscommsTask, (signed char*)"AHRSComms", STACK_SIZE, NULL, TASK_PRIORITY, &taskHandle);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t update_errors = 0;
|
|
||||||
static uint16_t attituderaw_errors = 0;
|
|
||||||
static uint16_t home_errors = 0;
|
|
||||||
static uint16_t calibration_errors = 0;
|
|
||||||
static uint16_t algorithm_errors = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module thread, should not return.
|
* Module thread, should not return.
|
||||||
*/
|
*/
|
||||||
static void ahrscommsTask(void *parameters)
|
static void ahrscommsTask(void* parameters)
|
||||||
{
|
{
|
||||||
enum opahrs_result result;
|
|
||||||
portTickType lastSysTime;
|
portTickType lastSysTime;
|
||||||
|
|
||||||
GPSGoodUpdates = 0;
|
|
||||||
|
|
||||||
AhrsStatusData data;
|
|
||||||
AhrsStatusGet(&data);
|
|
||||||
data.CalibrationSet = AHRSSTATUS_CALIBRATIONSET_FALSE;
|
|
||||||
AhrsStatusSet(&data);
|
|
||||||
|
|
||||||
// Main task loop
|
|
||||||
while (1) {
|
|
||||||
struct opahrs_msg_v1 rsp;
|
|
||||||
struct opahrs_msg_v1 req;
|
|
||||||
AhrsStatusData data;
|
AhrsStatusData data;
|
||||||
|
|
||||||
AlarmsSet(SYSTEMALARMS_ALARM_AHRSCOMMS, SYSTEMALARMS_ALARM_CRITICAL);
|
AlarmsSet(SYSTEMALARMS_ALARM_AHRSCOMMS, SYSTEMALARMS_ALARM_CRITICAL);
|
||||||
|
|
||||||
/* Spin here until we're in sync */
|
/*Until AHRS connects, assume it doesn't know home */
|
||||||
while (PIOS_OPAHRS_resync() != OPAHRS_RESULT_OK) {
|
|
||||||
vTaskDelay(100 / portTICK_RATE_MS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Give the other side a chance to keep up */
|
|
||||||
//vTaskDelay(100 / portTICK_RATE_MS);
|
|
||||||
|
|
||||||
if (PIOS_OPAHRS_GetSerial(&rsp) == OPAHRS_RESULT_OK) {
|
|
||||||
update_ahrs_status(&(rsp.payload.user.v.rsp.serial));
|
|
||||||
} else {
|
|
||||||
/* Comms error */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Whenever resyncing, assume AHRS doesn't reset and doesn't know home */
|
|
||||||
AhrsStatusGet(&data);
|
AhrsStatusGet(&data);
|
||||||
req.payload.user.v.req.initialized.initialized = AHRS_INIT_QUERY;
|
|
||||||
result = PIOS_OPAHRS_SetGetInitialized(&req, &rsp);
|
|
||||||
if ((result != OPAHRS_RESULT_OK) || (rsp.payload.user.v.rsp.initialized.initialized == AHRS_UNINITIALIZED)) {
|
|
||||||
data.Initialized = AHRSSTATUS_INITIALIZED_FALSE;
|
|
||||||
data.HomeSet = AHRSSTATUS_HOMESET_FALSE;
|
data.HomeSet = AHRSSTATUS_HOMESET_FALSE;
|
||||||
data.CalibrationSet = AHRSSTATUS_CALIBRATIONSET_FALSE;
|
//data.CalibrationSet = AHRSSTATUS_CALIBRATIONSET_FALSE;
|
||||||
data.AlgorithmSet = AHRSSTATUS_ALGORITHMSET_FALSE;
|
data.AlgorithmSet = AHRSSTATUS_CALIBRATIONSET_FALSE;
|
||||||
} else {
|
|
||||||
data.Initialized = AHRSSTATUS_INITIALIZED_TRUE;
|
|
||||||
AlarmsClear(SYSTEMALARMS_ALARM_AHRSCOMMS);
|
|
||||||
}
|
|
||||||
AhrsStatusSet(&data);
|
AhrsStatusSet(&data);
|
||||||
|
|
||||||
/* We're in sync with the AHRS, spin here until an error occurs */
|
// Main task loop
|
||||||
lastSysTime = xTaskGetTickCount();
|
while (1)
|
||||||
while (1) {
|
{
|
||||||
AHRSSettingsData settings;
|
AHRSSettingsData settings;
|
||||||
|
|
||||||
/* Update settings with latest value */
|
|
||||||
AHRSSettingsGet(&settings);
|
AHRSSettingsGet(&settings);
|
||||||
|
|
||||||
AhrsStatusGet(&data);
|
AhrsSendObjects();
|
||||||
if ((data.HomeSet == AHRSSTATUS_HOMESET_TRUE) && (data.CalibrationSet == AHRSSTATUS_CALIBRATIONSET_TRUE)
|
AhrsCommStatus stat = AhrsGetStatus();
|
||||||
&& (data.AlgorithmSet == AHRSSTATUS_ALGORITHMSET_TRUE)) {
|
if(stat.linkOk)
|
||||||
|
{
|
||||||
req.payload.user.v.req.initialized.initialized = AHRS_INITIALIZED;
|
|
||||||
if ((result = PIOS_OPAHRS_SetGetInitialized(&req, &rsp)) == OPAHRS_RESULT_OK) {
|
|
||||||
data.Initialized = AHRSSTATUS_INITIALIZED_TRUE;
|
|
||||||
AhrsStatusSet(&data);
|
|
||||||
PIOS_OPAHRS_SetGetInitialized(&req, &rsp);
|
|
||||||
AlarmsClear(SYSTEMALARMS_ALARM_AHRSCOMMS);
|
AlarmsClear(SYSTEMALARMS_ALARM_AHRSCOMMS);
|
||||||
} else {
|
}else
|
||||||
break;
|
{
|
||||||
|
AlarmsSet(SYSTEMALARMS_ALARM_AHRSCOMMS, SYSTEMALARMS_ALARM_WARNING);
|
||||||
}
|
}
|
||||||
}
|
AhrsStatusData sData;
|
||||||
// Update home coordinate if it hasn't been updated
|
AhrsStatusGet(&sData);
|
||||||
AhrsStatusGet(&data);
|
|
||||||
if (HomeLocationIsUpdatedFlag || (data.HomeSet == AHRSSTATUS_HOMESET_FALSE)) {
|
|
||||||
struct opahrs_msg_v1 req;
|
|
||||||
|
|
||||||
load_magnetic_north(&(req.payload.user.v.req.north));
|
sData.LinkRunning = stat.linkOk;
|
||||||
if ((result = PIOS_OPAHRS_SetMagNorth(&req)) == OPAHRS_RESULT_OK) {
|
sData.AhrsKickstarts = stat.remote.kickStarts;
|
||||||
HomeLocationIsUpdatedFlag = false;
|
sData.AhrsCrcErrors = stat.remote.crcErrors;
|
||||||
data.HomeSet = AHRSSTATUS_HOMESET_TRUE;
|
sData.AhrsRetries = stat.remote.retries;
|
||||||
AhrsStatusSet(&data);
|
sData.AhrsInvalidPackets = stat.remote.invalidPacket;
|
||||||
} else {
|
sData.OpCrcErrors = stat.local.crcErrors;
|
||||||
/* Comms error */
|
sData.OpRetries = stat.local.retries;
|
||||||
home_errors++;
|
sData.OpInvalidPackets = stat.local.invalidPacket;
|
||||||
data.HomeSet = AHRSSTATUS_HOMESET_FALSE;
|
|
||||||
AhrsStatusSet(&data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Update calibration if necessary
|
|
||||||
AhrsStatusGet(&data);
|
|
||||||
if (AHRSCalibrationIsUpdatedFlag || (data.CalibrationSet == AHRSSTATUS_CALIBRATIONSET_FALSE)) {
|
|
||||||
struct opahrs_msg_v1 req;
|
|
||||||
struct opahrs_msg_v1 rsp;
|
|
||||||
load_calibration(&(req.payload.user.v.req.calibration));
|
|
||||||
if ((result = PIOS_OPAHRS_SetGetCalibration(&req, &rsp)) == OPAHRS_RESULT_OK) {
|
|
||||||
update_calibration(&(rsp.payload.user.v.rsp.calibration));
|
|
||||||
AHRSCalibrationIsUpdatedFlag = false;
|
|
||||||
if (rsp.payload.user.v.req.calibration.measure_var != AHRS_ECHO)
|
|
||||||
data.CalibrationSet = AHRSSTATUS_CALIBRATIONSET_TRUE;
|
|
||||||
AhrsStatusSet(&data);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* Comms error */
|
|
||||||
data.CalibrationSet = AHRSSTATUS_CALIBRATIONSET_FALSE;
|
|
||||||
AhrsStatusSet(&data);
|
|
||||||
calibration_errors++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Update algorithm
|
|
||||||
if (AHRSSettingsIsUpdatedFlag || (data.AlgorithmSet == AHRSSTATUS_ALGORITHMSET_FALSE)) {
|
|
||||||
struct opahrs_msg_v1 req;
|
|
||||||
|
|
||||||
if (settings.Algorithm == AHRSSETTINGS_ALGORITHM_INSGPS)
|
|
||||||
req.payload.user.v.req.algorithm.algorithm = INSGPS_Algo;
|
|
||||||
if (settings.Algorithm == AHRSSETTINGS_ALGORITHM_SIMPLE)
|
|
||||||
req.payload.user.v.req.algorithm.algorithm = SIMPLE_Algo;
|
|
||||||
|
|
||||||
if ((result = PIOS_OPAHRS_SetAlgorithm(&req)) == OPAHRS_RESULT_OK) {
|
|
||||||
data.AlgorithmSet = AHRSSTATUS_ALGORITHMSET_TRUE;
|
|
||||||
AhrsStatusSet(&data);
|
|
||||||
} else {
|
|
||||||
/* Comms error */
|
|
||||||
data.AlgorithmSet = AHRSSTATUS_ALGORITHMSET_FALSE;
|
|
||||||
AhrsStatusSet(&data);
|
|
||||||
algorithm_errors++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If settings indicate, grab the raw and filtered data instead of estimate
|
|
||||||
if (settings.UpdateRaw) {
|
|
||||||
if ((result = PIOS_OPAHRS_GetAttitudeRaw(&rsp)) == OPAHRS_RESULT_OK) {
|
|
||||||
update_attitude_raw(&(rsp.payload.user.v.rsp.attituderaw));
|
|
||||||
} else {
|
|
||||||
/* Comms error */
|
|
||||||
attituderaw_errors++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (settings.UpdateFiltered) {
|
|
||||||
// Otherwise do standard technique
|
|
||||||
struct opahrs_msg_v1 req;
|
|
||||||
struct opahrs_msg_v1 rsp;
|
|
||||||
|
|
||||||
// Load barometer if updated
|
|
||||||
if (BaroAltitudeIsUpdatedFlag)
|
|
||||||
load_baro_altitude(&(req.payload.user.v.req.update));
|
|
||||||
else
|
|
||||||
req.payload.user.v.req.update.barometer.updated = 0;
|
|
||||||
|
|
||||||
// Load GPS if updated
|
|
||||||
if (GPSPositionIsUpdatedFlag)
|
|
||||||
load_gps_position(&(req.payload.user.v.req.update));
|
|
||||||
else
|
|
||||||
req.payload.user.v.req.update.gps.updated = 0;
|
|
||||||
|
|
||||||
// Transfer packet and process returned attitude
|
|
||||||
if ((result = PIOS_OPAHRS_SetGetUpdate(&req, &rsp)) == OPAHRS_RESULT_OK) {
|
|
||||||
if (req.payload.user.v.req.update.barometer.updated)
|
|
||||||
BaroAltitudeIsUpdatedFlag = false;
|
|
||||||
if (req.payload.user.v.req.update.gps.updated)
|
|
||||||
GPSPositionIsUpdatedFlag = false;
|
|
||||||
process_update(&(rsp.payload.user.v.rsp.update));
|
|
||||||
} else {
|
|
||||||
/* Comms error */
|
|
||||||
update_errors++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
AhrsStatusSet(&sData);
|
||||||
/* Wait for the next update interval */
|
/* Wait for the next update interval */
|
||||||
vTaskDelayUntil(&lastSysTime, settings.UpdatePeriod / portTICK_RATE_MS);
|
vTaskDelayUntil(&lastSysTime, settings.UpdatePeriod / portTICK_RATE_MS );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void load_calibration(struct opahrs_msg_v1_req_calibration *calibration)
|
|
||||||
{
|
|
||||||
AHRSCalibrationData data;
|
|
||||||
AHRSCalibrationGet(&data);
|
|
||||||
if (data.measure_var == AHRSCALIBRATION_MEASURE_VAR_SET)
|
|
||||||
calibration->measure_var = AHRS_SET;
|
|
||||||
else if (data.measure_var == AHRSCALIBRATION_MEASURE_VAR_MEASURE)
|
|
||||||
calibration->measure_var = AHRS_MEASURE;
|
|
||||||
else
|
|
||||||
calibration->measure_var = AHRS_ECHO;
|
|
||||||
|
|
||||||
calibration->accel_bias[0] = data.accel_bias[0];
|
|
||||||
calibration->accel_bias[1] = data.accel_bias[1];
|
|
||||||
calibration->accel_bias[2] = data.accel_bias[2];
|
|
||||||
calibration->accel_scale[0] = data.accel_scale[0];
|
|
||||||
calibration->accel_scale[1] = data.accel_scale[1];
|
|
||||||
calibration->accel_scale[2] = data.accel_scale[2];
|
|
||||||
calibration->accel_var[0] = data.accel_var[0];
|
|
||||||
calibration->accel_var[1] = data.accel_var[1];
|
|
||||||
calibration->accel_var[2] = data.accel_var[2];
|
|
||||||
calibration->gyro_bias[0] = data.gyro_bias[0];
|
|
||||||
calibration->gyro_bias[1] = data.gyro_bias[1];
|
|
||||||
calibration->gyro_bias[2] = data.gyro_bias[2];
|
|
||||||
calibration->gyro_scale[0] = data.gyro_scale[0];
|
|
||||||
calibration->gyro_scale[1] = data.gyro_scale[1];
|
|
||||||
calibration->gyro_scale[2] = data.gyro_scale[2];
|
|
||||||
calibration->gyro_var[0] = data.gyro_var[0];
|
|
||||||
calibration->gyro_var[1] = data.gyro_var[1];
|
|
||||||
calibration->gyro_var[2] = data.gyro_var[2];
|
|
||||||
calibration->mag_bias[0] = data.mag_bias[0];
|
|
||||||
calibration->mag_bias[1] = data.mag_bias[1];
|
|
||||||
calibration->mag_bias[2] = data.mag_bias[2];
|
|
||||||
calibration->mag_scale[0] = data.mag_scale[0];
|
|
||||||
calibration->mag_scale[1] = data.mag_scale[1];
|
|
||||||
calibration->mag_scale[2] = data.mag_scale[2];
|
|
||||||
calibration->mag_var[0] = data.mag_var[0];
|
|
||||||
calibration->mag_var[1] = data.mag_var[1];
|
|
||||||
calibration->mag_var[2] = data.mag_var[2];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_calibration(struct opahrs_msg_v1_rsp_calibration *calibration)
|
|
||||||
{
|
|
||||||
AHRSCalibrationData data;
|
|
||||||
AHRSCalibrationGet(&data);
|
|
||||||
|
|
||||||
AHRSCalibrationIsLocallyUpdateFlag = true;
|
|
||||||
data.accel_var[0] = calibration->accel_var[0];
|
|
||||||
data.accel_var[1] = calibration->accel_var[1];
|
|
||||||
data.accel_var[2] = calibration->accel_var[2];
|
|
||||||
data.gyro_var[0] = calibration->gyro_var[0];
|
|
||||||
data.gyro_var[1] = calibration->gyro_var[1];
|
|
||||||
data.gyro_var[2] = calibration->gyro_var[2];
|
|
||||||
data.mag_var[0] = calibration->mag_var[0];
|
|
||||||
data.mag_var[1] = calibration->mag_var[1];
|
|
||||||
data.mag_var[2] = calibration->mag_var[2];
|
|
||||||
AHRSCalibrationSet(&data);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void load_magnetic_north(struct opahrs_msg_v1_req_north *mag_north)
|
|
||||||
{
|
|
||||||
HomeLocationData data;
|
|
||||||
|
|
||||||
HomeLocationGet(&data);
|
|
||||||
mag_north->Be[0] = data.Be[0];
|
|
||||||
mag_north->Be[1] = data.Be[1];
|
|
||||||
mag_north->Be[2] = data.Be[2];
|
|
||||||
|
|
||||||
if (data.Be[0] == 0 && data.Be[1] == 0 && data.Be[2] == 0) {
|
|
||||||
// in case nothing has been set go to default to prevent NaN in attitude solution
|
|
||||||
mag_north->Be[0] = 1;
|
|
||||||
mag_north->Be[1] = 0;
|
|
||||||
mag_north->Be[2] = 0;
|
|
||||||
} else {
|
|
||||||
// normalize for unit length here
|
|
||||||
float len = sqrt(data.Be[0] * data.Be[0] + data.Be[1] * data.Be[1] + data.Be[2] * data.Be[2]);
|
|
||||||
mag_north->Be[0] = data.Be[0] / len;
|
|
||||||
mag_north->Be[1] = data.Be[1] / len;
|
|
||||||
mag_north->Be[2] = data.Be[2] / len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void load_baro_altitude(struct opahrs_msg_v1_req_update *update)
|
|
||||||
{
|
|
||||||
BaroAltitudeData data;
|
|
||||||
|
|
||||||
BaroAltitudeGet(&data);
|
|
||||||
|
|
||||||
update->barometer.altitude = data.Altitude;
|
|
||||||
update->barometer.updated = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void load_gps_position(struct opahrs_msg_v1_req_update *update)
|
|
||||||
{
|
|
||||||
GPSPositionData data;
|
|
||||||
GPSPositionGet(&data);
|
|
||||||
HomeLocationData home;
|
|
||||||
HomeLocationGet(&home);
|
|
||||||
|
|
||||||
update->gps.updated = TRUE;
|
|
||||||
|
|
||||||
if (home.Set == HOMELOCATION_SET_FALSE || home.Indoor == HOMELOCATION_INDOOR_TRUE) {
|
|
||||||
PositionActualData pos;
|
|
||||||
PositionActualGet(&pos);
|
|
||||||
|
|
||||||
update->gps.NED[0] = 0;
|
|
||||||
update->gps.NED[1] = 0;
|
|
||||||
update->gps.NED[2] = 0;
|
|
||||||
update->gps.groundspeed = 0;
|
|
||||||
update->gps.heading = 0;
|
|
||||||
update->gps.quality = -1; // indicates indoor mode, high variance zeros update
|
|
||||||
} else {
|
|
||||||
// TODO: Parameterize these heuristics into the settings
|
|
||||||
if (data.Satellites >= 7 && data.PDOP < 3.5) {
|
|
||||||
if (GPSGoodUpdates < 30) {
|
|
||||||
GPSGoodUpdates++;
|
|
||||||
update->gps.quality = 0;
|
|
||||||
} else {
|
|
||||||
update->gps.groundspeed = data.Groundspeed;
|
|
||||||
update->gps.heading = data.Heading;
|
|
||||||
double LLA[3] =
|
|
||||||
{ (double)data.Latitude / 1e7, (double)data.Longitude / 1e7, (double)(data.GeoidSeparation + data.Altitude) };
|
|
||||||
// convert from cm back to meters
|
|
||||||
double ECEF[3] = { (double)(home.ECEF[0] / 100), (double)(home.ECEF[1] / 100), (double)(home.ECEF[2] / 100) };
|
|
||||||
LLA2Base(LLA, ECEF, (float (*)[3])home.RNE, update->gps.NED);
|
|
||||||
update->gps.quality = 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
GPSGoodUpdates = 0;
|
|
||||||
update->gps.quality = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void process_update(struct opahrs_msg_v1_rsp_update *update)
|
|
||||||
{
|
|
||||||
AttitudeActualData data;
|
|
||||||
AttitudeSettingsData attitudeSettings;
|
|
||||||
AttitudeSettingsGet(&attitudeSettings);
|
|
||||||
|
|
||||||
data.q1 = update->quaternion.q1;
|
|
||||||
data.q2 = update->quaternion.q2;
|
|
||||||
data.q3 = update->quaternion.q3;
|
|
||||||
data.q4 = update->quaternion.q4;
|
|
||||||
|
|
||||||
float q[4] = { data.q1, data.q2, data.q3, data.q4 };
|
|
||||||
float rpy[3];
|
|
||||||
Quaternion2RPY(q, rpy);
|
|
||||||
data.Roll = rpy[0] - attitudeSettings.RollBias;
|
|
||||||
data.Pitch = rpy[1] - attitudeSettings.PitchBias;
|
|
||||||
data.Yaw = rpy[2];
|
|
||||||
if (data.Yaw < 0)
|
|
||||||
data.Yaw += 360;
|
|
||||||
|
|
||||||
AttitudeActualSet(&data);
|
|
||||||
|
|
||||||
PositionActualData pos;
|
|
||||||
PositionActualGet(&pos);
|
|
||||||
pos.North = update->NED[0];
|
|
||||||
pos.East = update->NED[1];
|
|
||||||
pos.Down = update->NED[2];
|
|
||||||
PositionActualSet(&pos);
|
|
||||||
|
|
||||||
VelocityActualData vel;
|
|
||||||
VelocityActualGet(&vel);
|
|
||||||
vel.North = update->Vel[0];
|
|
||||||
vel.East = update->Vel[1];
|
|
||||||
vel.Down = update->Vel[2];
|
|
||||||
VelocityActualSet(&vel);
|
|
||||||
|
|
||||||
AhrsStatusData status;
|
|
||||||
AhrsStatusGet(&status);
|
|
||||||
status.CPULoad = update->load;
|
|
||||||
status.IdleTimePerCyle = update->idle_time;
|
|
||||||
status.RunningTimePerCyle = update->run_time;
|
|
||||||
status.DroppedUpdates = update->dropped_updates;
|
|
||||||
AhrsStatusSet(&status);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_attitude_raw(struct opahrs_msg_v1_rsp_attituderaw *attituderaw)
|
|
||||||
{
|
|
||||||
AttitudeRawData data;
|
|
||||||
|
|
||||||
data.magnetometers[ATTITUDERAW_MAGNETOMETERS_X] = attituderaw->mags.x;
|
|
||||||
data.magnetometers[ATTITUDERAW_MAGNETOMETERS_Y] = attituderaw->mags.y;
|
|
||||||
data.magnetometers[ATTITUDERAW_MAGNETOMETERS_Z] = attituderaw->mags.z;
|
|
||||||
|
|
||||||
data.gyros[ATTITUDERAW_GYROS_X] = attituderaw->gyros.x;
|
|
||||||
data.gyros[ATTITUDERAW_GYROS_Y] = attituderaw->gyros.y;
|
|
||||||
data.gyros[ATTITUDERAW_GYROS_Z] = attituderaw->gyros.z;
|
|
||||||
|
|
||||||
data.gyros_filtered[ATTITUDERAW_GYROS_FILTERED_X] = attituderaw->gyros_filtered.x;
|
|
||||||
data.gyros_filtered[ATTITUDERAW_GYROS_FILTERED_Y] = attituderaw->gyros_filtered.y;
|
|
||||||
data.gyros_filtered[ATTITUDERAW_GYROS_FILTERED_Z] = attituderaw->gyros_filtered.z;
|
|
||||||
|
|
||||||
data.gyrotemp[ATTITUDERAW_GYROTEMP_XY] = attituderaw->gyros.xy_temp;
|
|
||||||
data.gyrotemp[ATTITUDERAW_GYROTEMP_Z] = attituderaw->gyros.z_temp;
|
|
||||||
|
|
||||||
data.accels[ATTITUDERAW_ACCELS_X] = attituderaw->accels.x;
|
|
||||||
data.accels[ATTITUDERAW_ACCELS_Y] = attituderaw->accels.y;
|
|
||||||
data.accels[ATTITUDERAW_ACCELS_Z] = attituderaw->accels.z;
|
|
||||||
|
|
||||||
data.accels_filtered[ATTITUDERAW_ACCELS_FILTERED_X] = attituderaw->accels_filtered.x;
|
|
||||||
data.accels_filtered[ATTITUDERAW_ACCELS_FILTERED_Y] = attituderaw->accels_filtered.y;
|
|
||||||
data.accels_filtered[ATTITUDERAW_ACCELS_FILTERED_Z] = attituderaw->accels_filtered.z;
|
|
||||||
|
|
||||||
AttitudeRawSet(&data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_ahrs_status(struct opahrs_msg_v1_rsp_serial *serial)
|
|
||||||
{
|
|
||||||
AhrsStatusData data;
|
|
||||||
|
|
||||||
// Get the current object data
|
|
||||||
AhrsStatusGet(&data);
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < sizeof(serial->serial_bcd); i++) {
|
|
||||||
data.SerialNumber[i] = serial->serial_bcd[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
data.CommErrors[AHRSSTATUS_COMMERRORS_UPDATE] = update_errors;
|
|
||||||
data.CommErrors[AHRSSTATUS_COMMERRORS_ATTITUDERAW] = attituderaw_errors;
|
|
||||||
data.CommErrors[AHRSSTATUS_COMMERRORS_HOMELOCATION] = home_errors;
|
|
||||||
data.CommErrors[AHRSSTATUS_COMMERRORS_CALIBRATION] = calibration_errors;
|
|
||||||
data.CommErrors[AHRSSTATUS_COMMERRORS_ALGORITHM] = algorithm_errors;
|
|
||||||
|
|
||||||
AhrsStatusSet(&data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
|
@ -35,3 +35,4 @@
|
|||||||
int32_t AHRSCommsInitialize(void);
|
int32_t AHRSCommsInitialize(void);
|
||||||
|
|
||||||
#endif // AHRS_COMMS_H
|
#endif // AHRS_COMMS_H
|
||||||
|
|
||||||
|
@ -1,111 +0,0 @@
|
|||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* @addtogroup UAVObjects OpenPilot UAVObjects
|
|
||||||
* @{
|
|
||||||
* @addtogroup AhrsStatus2 AhrsStatus2
|
|
||||||
* @brief Status for the @ref AHRSCommsModule, including communication errors
|
|
||||||
*
|
|
||||||
* Autogenerated files and functions for AhrsStatus2 Object
|
|
||||||
* @{
|
|
||||||
*
|
|
||||||
* @file ahrsstatus2.c
|
|
||||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
|
||||||
* @brief Implementation of the AhrsStatus2 object. This file has been
|
|
||||||
* automatically generated by the UAVObjectGenerator.
|
|
||||||
*
|
|
||||||
* @note Object definition file: ahrsstatus2.xml.
|
|
||||||
* This is an automatically generated file.
|
|
||||||
* DO NOT modify manually.
|
|
||||||
*
|
|
||||||
* @see The GNU Public License (GPL) Version 3
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
/*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "openpilot.h"
|
|
||||||
#include "ahrsstatus2.h"
|
|
||||||
|
|
||||||
// Private variables
|
|
||||||
static UAVObjHandle handle;
|
|
||||||
|
|
||||||
// Private functions
|
|
||||||
static void setDefaults(UAVObjHandle obj, uint16_t instId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize object.
|
|
||||||
* \return 0 Success
|
|
||||||
* \return -1 Failure
|
|
||||||
*/
|
|
||||||
int32_t AhrsStatus2Initialize()
|
|
||||||
{
|
|
||||||
// Register object with the object manager
|
|
||||||
handle = UAVObjRegister(AHRSSTATUS2_OBJID, AHRSSTATUS2_NAME, AHRSSTATUS2_METANAME, 0,
|
|
||||||
AHRSSTATUS2_ISSINGLEINST, AHRSSTATUS2_ISSETTINGS, AHRSSTATUS2_NUMBYTES, &setDefaults);
|
|
||||||
|
|
||||||
// Done
|
|
||||||
if (handle != 0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize object fields and metadata with the default values.
|
|
||||||
* If a default value is not specified the object fields
|
|
||||||
* will be initialized to zero.
|
|
||||||
*/
|
|
||||||
static void setDefaults(UAVObjHandle obj, uint16_t instId)
|
|
||||||
{
|
|
||||||
AhrsStatus2Data data;
|
|
||||||
UAVObjMetadata metadata;
|
|
||||||
|
|
||||||
// Initialize object fields to their default values
|
|
||||||
UAVObjGetInstanceData(obj, instId, &data);
|
|
||||||
memset(&data, 0, sizeof(AhrsStatus2Data));
|
|
||||||
|
|
||||||
UAVObjSetInstanceData(obj, instId, &data);
|
|
||||||
|
|
||||||
// Initialize object metadata to their default values
|
|
||||||
metadata.access = ACCESS_READWRITE;
|
|
||||||
metadata.gcsAccess = ACCESS_READWRITE;
|
|
||||||
metadata.telemetryAcked = 0;
|
|
||||||
metadata.telemetryUpdateMode = UPDATEMODE_PERIODIC;
|
|
||||||
metadata.telemetryUpdatePeriod = 1000;
|
|
||||||
metadata.gcsTelemetryAcked = 0;
|
|
||||||
metadata.gcsTelemetryUpdateMode = UPDATEMODE_MANUAL;
|
|
||||||
metadata.gcsTelemetryUpdatePeriod = 0;
|
|
||||||
metadata.loggingUpdateMode = UPDATEMODE_PERIODIC;
|
|
||||||
metadata.loggingUpdatePeriod = 1000;
|
|
||||||
UAVObjSetMetadata(obj, &metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get object handle
|
|
||||||
*/
|
|
||||||
UAVObjHandle AhrsStatus2Handle()
|
|
||||||
{
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
@ -41,7 +41,7 @@
|
|||||||
#define AHRSSTATUS_H
|
#define AHRSSTATUS_H
|
||||||
|
|
||||||
// Object constants
|
// Object constants
|
||||||
#define AHRSSTATUS_OBJID 4061809000U
|
#define AHRSSTATUS_OBJID 188215176U
|
||||||
#define AHRSSTATUS_NAME "AhrsStatus"
|
#define AHRSSTATUS_NAME "AhrsStatus"
|
||||||
#define AHRSSTATUS_METANAME "AhrsStatusMeta"
|
#define AHRSSTATUS_METANAME "AhrsStatusMeta"
|
||||||
#define AHRSSTATUS_ISSINGLEINST 1
|
#define AHRSSTATUS_ISSINGLEINST 1
|
||||||
@ -71,35 +71,33 @@
|
|||||||
|
|
||||||
// Object data
|
// Object data
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t SerialNumber[25];
|
uint8_t SerialNumber[8];
|
||||||
uint8_t CPULoad;
|
uint8_t CPULoad;
|
||||||
uint8_t IdleTimePerCyle;
|
uint8_t IdleTimePerCyle;
|
||||||
uint8_t RunningTimePerCyle;
|
uint8_t RunningTimePerCyle;
|
||||||
uint8_t DroppedUpdates;
|
uint8_t DroppedUpdates;
|
||||||
uint8_t CommErrors[5];
|
|
||||||
uint8_t Initialized;
|
|
||||||
uint8_t AlgorithmSet;
|
uint8_t AlgorithmSet;
|
||||||
uint8_t CalibrationSet;
|
uint8_t CalibrationSet;
|
||||||
uint8_t HomeSet;
|
uint8_t HomeSet;
|
||||||
|
uint8_t LinkRunning;
|
||||||
|
uint8_t AhrsKickstarts;
|
||||||
|
uint8_t AhrsCrcErrors;
|
||||||
|
uint8_t AhrsRetries;
|
||||||
|
uint8_t AhrsInvalidPackets;
|
||||||
|
uint8_t OpCrcErrors;
|
||||||
|
uint8_t OpRetries;
|
||||||
|
uint8_t OpInvalidPackets;
|
||||||
|
|
||||||
} __attribute__((packed)) AhrsStatusData;
|
} __attribute__((packed)) AhrsStatusData;
|
||||||
|
|
||||||
// Field information
|
// Field information
|
||||||
// Field SerialNumber information
|
// Field SerialNumber information
|
||||||
/* Number of elements for field SerialNumber */
|
/* Number of elements for field SerialNumber */
|
||||||
#define AHRSSTATUS_SERIALNUMBER_NUMELEM 25
|
#define AHRSSTATUS_SERIALNUMBER_NUMELEM 8
|
||||||
// Field CPULoad information
|
// Field CPULoad information
|
||||||
// Field IdleTimePerCyle information
|
// Field IdleTimePerCyle information
|
||||||
// Field RunningTimePerCyle information
|
// Field RunningTimePerCyle information
|
||||||
// Field DroppedUpdates information
|
// Field DroppedUpdates information
|
||||||
// Field CommErrors information
|
|
||||||
/* Array element names for field CommErrors */
|
|
||||||
typedef enum { AHRSSTATUS_COMMERRORS_ALGORITHM=0, AHRSSTATUS_COMMERRORS_UPDATE=1, AHRSSTATUS_COMMERRORS_ATTITUDERAW=2, AHRSSTATUS_COMMERRORS_HOMELOCATION=3, AHRSSTATUS_COMMERRORS_CALIBRATION=4 } AhrsStatusCommErrorsElem;
|
|
||||||
/* Number of elements for field CommErrors */
|
|
||||||
#define AHRSSTATUS_COMMERRORS_NUMELEM 5
|
|
||||||
// Field Initialized information
|
|
||||||
/* Enumeration options for field Initialized */
|
|
||||||
typedef enum { AHRSSTATUS_INITIALIZED_FALSE=0, AHRSSTATUS_INITIALIZED_TRUE=1 } AhrsStatusInitializedOptions;
|
|
||||||
// Field AlgorithmSet information
|
// Field AlgorithmSet information
|
||||||
/* Enumeration options for field AlgorithmSet */
|
/* Enumeration options for field AlgorithmSet */
|
||||||
typedef enum { AHRSSTATUS_ALGORITHMSET_FALSE=0, AHRSSTATUS_ALGORITHMSET_TRUE=1 } AhrsStatusAlgorithmSetOptions;
|
typedef enum { AHRSSTATUS_ALGORITHMSET_FALSE=0, AHRSSTATUS_ALGORITHMSET_TRUE=1 } AhrsStatusAlgorithmSetOptions;
|
||||||
@ -109,6 +107,16 @@ typedef enum { AHRSSTATUS_CALIBRATIONSET_FALSE=0, AHRSSTATUS_CALIBRATIONSET_TRUE
|
|||||||
// Field HomeSet information
|
// Field HomeSet information
|
||||||
/* Enumeration options for field HomeSet */
|
/* Enumeration options for field HomeSet */
|
||||||
typedef enum { AHRSSTATUS_HOMESET_FALSE=0, AHRSSTATUS_HOMESET_TRUE=1 } AhrsStatusHomeSetOptions;
|
typedef enum { AHRSSTATUS_HOMESET_FALSE=0, AHRSSTATUS_HOMESET_TRUE=1 } AhrsStatusHomeSetOptions;
|
||||||
|
// Field LinkRunning information
|
||||||
|
/* Enumeration options for field LinkRunning */
|
||||||
|
typedef enum { AHRSSTATUS_LINKRUNNING_FALSE=0, AHRSSTATUS_LINKRUNNING_TRUE=1 } AhrsStatusLinkRunningOptions;
|
||||||
|
// Field AhrsKickstarts information
|
||||||
|
// Field AhrsCrcErrors information
|
||||||
|
// Field AhrsRetries information
|
||||||
|
// Field AhrsInvalidPackets information
|
||||||
|
// Field OpCrcErrors information
|
||||||
|
// Field OpRetries information
|
||||||
|
// Field OpInvalidPackets information
|
||||||
|
|
||||||
|
|
||||||
// Generic interface functions
|
// Generic interface functions
|
||||||
|
@ -1,131 +0,0 @@
|
|||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* @addtogroup UAVObjects OpenPilot UAVObjects
|
|
||||||
* @{
|
|
||||||
* @addtogroup AhrsStatus2 AhrsStatus2
|
|
||||||
* @brief Status for the @ref AHRSCommsModule, including communication errors
|
|
||||||
*
|
|
||||||
* Autogenerated files and functions for AhrsStatus2 Object
|
|
||||||
|
|
||||||
* @{
|
|
||||||
*
|
|
||||||
* @file ahrsstatus2.h
|
|
||||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
|
||||||
* @brief Implementation of the AhrsStatus2 object. This file has been
|
|
||||||
* automatically generated by the UAVObjectGenerator.
|
|
||||||
*
|
|
||||||
* @note Object definition file: ahrsstatus2.xml.
|
|
||||||
* This is an automatically generated file.
|
|
||||||
* DO NOT modify manually.
|
|
||||||
*
|
|
||||||
* @see The GNU Public License (GPL) Version 3
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
/*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef AHRSSTATUS2_H
|
|
||||||
#define AHRSSTATUS2_H
|
|
||||||
|
|
||||||
// Object constants
|
|
||||||
#define AHRSSTATUS2_OBJID 805003662U
|
|
||||||
#define AHRSSTATUS2_NAME "AhrsStatus2"
|
|
||||||
#define AHRSSTATUS2_METANAME "AhrsStatus2Meta"
|
|
||||||
#define AHRSSTATUS2_ISSINGLEINST 1
|
|
||||||
#define AHRSSTATUS2_ISSETTINGS 0
|
|
||||||
#define AHRSSTATUS2_NUMBYTES sizeof(AhrsStatus2Data)
|
|
||||||
|
|
||||||
// Object access macros
|
|
||||||
/**
|
|
||||||
* @function AhrsStatus2Get(dataOut)
|
|
||||||
* @brief Populate a AhrsStatus2Data object
|
|
||||||
* @param[out] dataOut
|
|
||||||
*/
|
|
||||||
#define AhrsStatus2Get(dataOut) UAVObjGetData(AhrsStatus2Handle(), dataOut)
|
|
||||||
#define AhrsStatus2Set(dataIn) UAVObjSetData(AhrsStatus2Handle(), dataIn)
|
|
||||||
#define AhrsStatus2InstGet(instId, dataOut) UAVObjGetInstanceData(AhrsStatus2Handle(), instId, dataOut)
|
|
||||||
#define AhrsStatus2InstSet(instId, dataIn) UAVObjSetInstanceData(AhrsStatus2Handle(), instId, dataIn)
|
|
||||||
#define AhrsStatus2ConnectQueue(queue) UAVObjConnectQueue(AhrsStatus2Handle(), queue, EV_MASK_ALL_UPDATES)
|
|
||||||
#define AhrsStatus2ConnectCallback(cb) UAVObjConnectCallback(AhrsStatus2Handle(), cb, EV_MASK_ALL_UPDATES)
|
|
||||||
#define AhrsStatus2CreateInstance() UAVObjCreateInstance(AhrsStatus2Handle())
|
|
||||||
#define AhrsStatus2RequestUpdate() UAVObjRequestUpdate(AhrsStatus2Handle())
|
|
||||||
#define AhrsStatus2RequestInstUpdate(instId) UAVObjRequestInstanceUpdate(AhrsStatus2Handle(), instId)
|
|
||||||
#define AhrsStatus2Updated() UAVObjUpdated(AhrsStatus2Handle())
|
|
||||||
#define AhrsStatus2InstUpdated(instId) UAVObjUpdated(AhrsStatus2Handle(), instId)
|
|
||||||
#define AhrsStatus2GetMetadata(dataOut) UAVObjGetMetadata(AhrsStatus2Handle(), dataOut)
|
|
||||||
#define AhrsStatus2SetMetadata(dataIn) UAVObjSetMetadata(AhrsStatus2Handle(), dataIn)
|
|
||||||
#define AhrsStatus2ReadOnly(dataIn) UAVObjReadOnly(AhrsStatus2Handle())
|
|
||||||
|
|
||||||
// Object data
|
|
||||||
typedef struct {
|
|
||||||
uint8_t SerialNumber[8];
|
|
||||||
uint8_t CPULoad;
|
|
||||||
uint8_t IdleTimePerCyle;
|
|
||||||
uint8_t RunningTimePerCyle;
|
|
||||||
uint8_t DroppedUpdates;
|
|
||||||
uint8_t AlgorithmSet;
|
|
||||||
uint8_t CalibrationSet;
|
|
||||||
uint8_t HomeSet;
|
|
||||||
uint8_t LinkRunning;
|
|
||||||
uint8_t AhrsKickstarts;
|
|
||||||
uint8_t AhrsCrcErrors;
|
|
||||||
uint8_t AhrsRetries;
|
|
||||||
uint8_t AhrsInvalidPackets;
|
|
||||||
uint8_t OpCrcErrors;
|
|
||||||
uint8_t OpRetries;
|
|
||||||
uint8_t OpInvalidPackets;
|
|
||||||
|
|
||||||
} __attribute__((packed)) AhrsStatus2Data;
|
|
||||||
|
|
||||||
// Field information
|
|
||||||
// Field SerialNumber information
|
|
||||||
/* Number of elements for field SerialNumber */
|
|
||||||
#define AHRSSTATUS2_SERIALNUMBER_NUMELEM 8
|
|
||||||
// Field CPULoad information
|
|
||||||
// Field IdleTimePerCyle information
|
|
||||||
// Field RunningTimePerCyle information
|
|
||||||
// Field DroppedUpdates information
|
|
||||||
// Field AlgorithmSet information
|
|
||||||
/* Enumeration options for field AlgorithmSet */
|
|
||||||
typedef enum { AHRSSTATUS2_ALGORITHMSET_FALSE=0, AHRSSTATUS2_ALGORITHMSET_TRUE=1 } AhrsStatus2AlgorithmSetOptions;
|
|
||||||
// Field CalibrationSet information
|
|
||||||
/* Enumeration options for field CalibrationSet */
|
|
||||||
typedef enum { AHRSSTATUS2_CALIBRATIONSET_FALSE=0, AHRSSTATUS2_CALIBRATIONSET_TRUE=1 } AhrsStatus2CalibrationSetOptions;
|
|
||||||
// Field HomeSet information
|
|
||||||
/* Enumeration options for field HomeSet */
|
|
||||||
typedef enum { AHRSSTATUS2_HOMESET_FALSE=0, AHRSSTATUS2_HOMESET_TRUE=1 } AhrsStatus2HomeSetOptions;
|
|
||||||
// Field LinkRunning information
|
|
||||||
/* Enumeration options for field LinkRunning */
|
|
||||||
typedef enum { AHRSSTATUS2_LINKRUNNING_FALSE=0, AHRSSTATUS2_LINKRUNNING_TRUE=1 } AhrsStatus2LinkRunningOptions;
|
|
||||||
// Field AhrsKickstarts information
|
|
||||||
// Field AhrsCrcErrors information
|
|
||||||
// Field AhrsRetries information
|
|
||||||
// Field AhrsInvalidPackets information
|
|
||||||
// Field OpCrcErrors information
|
|
||||||
// Field OpRetries information
|
|
||||||
// Field OpInvalidPackets information
|
|
||||||
|
|
||||||
|
|
||||||
// Generic interface functions
|
|
||||||
int32_t AhrsStatus2Initialize();
|
|
||||||
UAVObjHandle AhrsStatus2Handle();
|
|
||||||
|
|
||||||
#endif // AHRSSTATUS2_H
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
* @}
|
|
||||||
*/
|
|
@ -34,7 +34,6 @@
|
|||||||
#include "ahrscalibration.h"
|
#include "ahrscalibration.h"
|
||||||
#include "ahrssettings.h"
|
#include "ahrssettings.h"
|
||||||
#include "ahrsstatus.h"
|
#include "ahrsstatus.h"
|
||||||
#include "ahrsstatus2.h"
|
|
||||||
#include "attitudeactual.h"
|
#include "attitudeactual.h"
|
||||||
#include "attitudedesired.h"
|
#include "attitudedesired.h"
|
||||||
#include "attituderaw.h"
|
#include "attituderaw.h"
|
||||||
@ -81,7 +80,6 @@ void UAVObjectsInitializeAll()
|
|||||||
AHRSCalibrationInitialize();
|
AHRSCalibrationInitialize();
|
||||||
AHRSSettingsInitialize();
|
AHRSSettingsInitialize();
|
||||||
AhrsStatusInitialize();
|
AhrsStatusInitialize();
|
||||||
AhrsStatus2Initialize();
|
|
||||||
AttitudeActualInitialize();
|
AttitudeActualInitialize();
|
||||||
AttitudeDesiredInitialize();
|
AttitudeDesiredInitialize();
|
||||||
AttitudeRawInitialize();
|
AttitudeRawInitialize();
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
#ifndef STM32103CB_AHRS_H_
|
#ifndef STM32103CB_AHRS_H_
|
||||||
#define STM32103CB_AHRS_H_
|
#define STM32103CB_AHRS_H_
|
||||||
|
|
||||||
|
|
||||||
//------------------------
|
//------------------------
|
||||||
// Timers and Channels Used
|
// Timers and Channels Used
|
||||||
//------------------------
|
//------------------------
|
||||||
|
@ -51,23 +51,6 @@ AhrsStatus::AhrsStatus(): UAVDataObject(OBJID, ISSINGLEINST, ISSETTINGS, NAME)
|
|||||||
SerialNumberElemNames.append("5");
|
SerialNumberElemNames.append("5");
|
||||||
SerialNumberElemNames.append("6");
|
SerialNumberElemNames.append("6");
|
||||||
SerialNumberElemNames.append("7");
|
SerialNumberElemNames.append("7");
|
||||||
SerialNumberElemNames.append("8");
|
|
||||||
SerialNumberElemNames.append("9");
|
|
||||||
SerialNumberElemNames.append("10");
|
|
||||||
SerialNumberElemNames.append("11");
|
|
||||||
SerialNumberElemNames.append("12");
|
|
||||||
SerialNumberElemNames.append("13");
|
|
||||||
SerialNumberElemNames.append("14");
|
|
||||||
SerialNumberElemNames.append("15");
|
|
||||||
SerialNumberElemNames.append("16");
|
|
||||||
SerialNumberElemNames.append("17");
|
|
||||||
SerialNumberElemNames.append("18");
|
|
||||||
SerialNumberElemNames.append("19");
|
|
||||||
SerialNumberElemNames.append("20");
|
|
||||||
SerialNumberElemNames.append("21");
|
|
||||||
SerialNumberElemNames.append("22");
|
|
||||||
SerialNumberElemNames.append("23");
|
|
||||||
SerialNumberElemNames.append("24");
|
|
||||||
fields.append( new UAVObjectField(QString("SerialNumber"), QString("n/a"), UAVObjectField::UINT8, SerialNumberElemNames, QStringList()) );
|
fields.append( new UAVObjectField(QString("SerialNumber"), QString("n/a"), UAVObjectField::UINT8, SerialNumberElemNames, QStringList()) );
|
||||||
QStringList CPULoadElemNames;
|
QStringList CPULoadElemNames;
|
||||||
CPULoadElemNames.append("0");
|
CPULoadElemNames.append("0");
|
||||||
@ -81,19 +64,6 @@ AhrsStatus::AhrsStatus(): UAVDataObject(OBJID, ISSINGLEINST, ISSETTINGS, NAME)
|
|||||||
QStringList DroppedUpdatesElemNames;
|
QStringList DroppedUpdatesElemNames;
|
||||||
DroppedUpdatesElemNames.append("0");
|
DroppedUpdatesElemNames.append("0");
|
||||||
fields.append( new UAVObjectField(QString("DroppedUpdates"), QString("count"), UAVObjectField::UINT8, DroppedUpdatesElemNames, QStringList()) );
|
fields.append( new UAVObjectField(QString("DroppedUpdates"), QString("count"), UAVObjectField::UINT8, DroppedUpdatesElemNames, QStringList()) );
|
||||||
QStringList CommErrorsElemNames;
|
|
||||||
CommErrorsElemNames.append("Algorithm");
|
|
||||||
CommErrorsElemNames.append("Update");
|
|
||||||
CommErrorsElemNames.append("AttitudeRaw");
|
|
||||||
CommErrorsElemNames.append("HomeLocation");
|
|
||||||
CommErrorsElemNames.append("Calibration");
|
|
||||||
fields.append( new UAVObjectField(QString("CommErrors"), QString("count"), UAVObjectField::UINT8, CommErrorsElemNames, QStringList()) );
|
|
||||||
QStringList InitializedElemNames;
|
|
||||||
InitializedElemNames.append("0");
|
|
||||||
QStringList InitializedEnumOptions;
|
|
||||||
InitializedEnumOptions.append("FALSE");
|
|
||||||
InitializedEnumOptions.append("TRUE");
|
|
||||||
fields.append( new UAVObjectField(QString("Initialized"), QString(""), UAVObjectField::ENUM, InitializedElemNames, InitializedEnumOptions) );
|
|
||||||
QStringList AlgorithmSetElemNames;
|
QStringList AlgorithmSetElemNames;
|
||||||
AlgorithmSetElemNames.append("0");
|
AlgorithmSetElemNames.append("0");
|
||||||
QStringList AlgorithmSetEnumOptions;
|
QStringList AlgorithmSetEnumOptions;
|
||||||
@ -112,6 +82,33 @@ AhrsStatus::AhrsStatus(): UAVDataObject(OBJID, ISSINGLEINST, ISSETTINGS, NAME)
|
|||||||
HomeSetEnumOptions.append("FALSE");
|
HomeSetEnumOptions.append("FALSE");
|
||||||
HomeSetEnumOptions.append("TRUE");
|
HomeSetEnumOptions.append("TRUE");
|
||||||
fields.append( new UAVObjectField(QString("HomeSet"), QString(""), UAVObjectField::ENUM, HomeSetElemNames, HomeSetEnumOptions) );
|
fields.append( new UAVObjectField(QString("HomeSet"), QString(""), UAVObjectField::ENUM, HomeSetElemNames, HomeSetEnumOptions) );
|
||||||
|
QStringList LinkRunningElemNames;
|
||||||
|
LinkRunningElemNames.append("0");
|
||||||
|
QStringList LinkRunningEnumOptions;
|
||||||
|
LinkRunningEnumOptions.append("FALSE");
|
||||||
|
LinkRunningEnumOptions.append("TRUE");
|
||||||
|
fields.append( new UAVObjectField(QString("LinkRunning"), QString(""), UAVObjectField::ENUM, LinkRunningElemNames, LinkRunningEnumOptions) );
|
||||||
|
QStringList AhrsKickstartsElemNames;
|
||||||
|
AhrsKickstartsElemNames.append("0");
|
||||||
|
fields.append( new UAVObjectField(QString("AhrsKickstarts"), QString("count"), UAVObjectField::UINT8, AhrsKickstartsElemNames, QStringList()) );
|
||||||
|
QStringList AhrsCrcErrorsElemNames;
|
||||||
|
AhrsCrcErrorsElemNames.append("0");
|
||||||
|
fields.append( new UAVObjectField(QString("AhrsCrcErrors"), QString("count"), UAVObjectField::UINT8, AhrsCrcErrorsElemNames, QStringList()) );
|
||||||
|
QStringList AhrsRetriesElemNames;
|
||||||
|
AhrsRetriesElemNames.append("0");
|
||||||
|
fields.append( new UAVObjectField(QString("AhrsRetries"), QString("count"), UAVObjectField::UINT8, AhrsRetriesElemNames, QStringList()) );
|
||||||
|
QStringList AhrsInvalidPacketsElemNames;
|
||||||
|
AhrsInvalidPacketsElemNames.append("0");
|
||||||
|
fields.append( new UAVObjectField(QString("AhrsInvalidPackets"), QString("count"), UAVObjectField::UINT8, AhrsInvalidPacketsElemNames, QStringList()) );
|
||||||
|
QStringList OpCrcErrorsElemNames;
|
||||||
|
OpCrcErrorsElemNames.append("0");
|
||||||
|
fields.append( new UAVObjectField(QString("OpCrcErrors"), QString("count"), UAVObjectField::UINT8, OpCrcErrorsElemNames, QStringList()) );
|
||||||
|
QStringList OpRetriesElemNames;
|
||||||
|
OpRetriesElemNames.append("0");
|
||||||
|
fields.append( new UAVObjectField(QString("OpRetries"), QString("count"), UAVObjectField::UINT8, OpRetriesElemNames, QStringList()) );
|
||||||
|
QStringList OpInvalidPacketsElemNames;
|
||||||
|
OpInvalidPacketsElemNames.append("0");
|
||||||
|
fields.append( new UAVObjectField(QString("OpInvalidPackets"), QString("count"), UAVObjectField::UINT8, OpInvalidPacketsElemNames, QStringList()) );
|
||||||
|
|
||||||
// Initialize object
|
// Initialize object
|
||||||
initializeFields(fields, (quint8*)&data, NUMBYTES);
|
initializeFields(fields, (quint8*)&data, NUMBYTES);
|
||||||
|
@ -43,35 +43,33 @@ class UAVOBJECTS_EXPORT AhrsStatus: public UAVDataObject
|
|||||||
public:
|
public:
|
||||||
// Field structure
|
// Field structure
|
||||||
typedef struct {
|
typedef struct {
|
||||||
quint8 SerialNumber[25];
|
quint8 SerialNumber[8];
|
||||||
quint8 CPULoad;
|
quint8 CPULoad;
|
||||||
quint8 IdleTimePerCyle;
|
quint8 IdleTimePerCyle;
|
||||||
quint8 RunningTimePerCyle;
|
quint8 RunningTimePerCyle;
|
||||||
quint8 DroppedUpdates;
|
quint8 DroppedUpdates;
|
||||||
quint8 CommErrors[5];
|
|
||||||
quint8 Initialized;
|
|
||||||
quint8 AlgorithmSet;
|
quint8 AlgorithmSet;
|
||||||
quint8 CalibrationSet;
|
quint8 CalibrationSet;
|
||||||
quint8 HomeSet;
|
quint8 HomeSet;
|
||||||
|
quint8 LinkRunning;
|
||||||
|
quint8 AhrsKickstarts;
|
||||||
|
quint8 AhrsCrcErrors;
|
||||||
|
quint8 AhrsRetries;
|
||||||
|
quint8 AhrsInvalidPackets;
|
||||||
|
quint8 OpCrcErrors;
|
||||||
|
quint8 OpRetries;
|
||||||
|
quint8 OpInvalidPackets;
|
||||||
|
|
||||||
} __attribute__((packed)) DataFields;
|
} __attribute__((packed)) DataFields;
|
||||||
|
|
||||||
// Field information
|
// Field information
|
||||||
// Field SerialNumber information
|
// Field SerialNumber information
|
||||||
/* Number of elements for field SerialNumber */
|
/* Number of elements for field SerialNumber */
|
||||||
static const quint32 SERIALNUMBER_NUMELEM = 25;
|
static const quint32 SERIALNUMBER_NUMELEM = 8;
|
||||||
// Field CPULoad information
|
// Field CPULoad information
|
||||||
// Field IdleTimePerCyle information
|
// Field IdleTimePerCyle information
|
||||||
// Field RunningTimePerCyle information
|
// Field RunningTimePerCyle information
|
||||||
// Field DroppedUpdates information
|
// Field DroppedUpdates information
|
||||||
// Field CommErrors information
|
|
||||||
/* Array element names for field CommErrors */
|
|
||||||
typedef enum { COMMERRORS_ALGORITHM=0, COMMERRORS_UPDATE=1, COMMERRORS_ATTITUDERAW=2, COMMERRORS_HOMELOCATION=3, COMMERRORS_CALIBRATION=4 } CommErrorsElem;
|
|
||||||
/* Number of elements for field CommErrors */
|
|
||||||
static const quint32 COMMERRORS_NUMELEM = 5;
|
|
||||||
// Field Initialized information
|
|
||||||
/* Enumeration options for field Initialized */
|
|
||||||
typedef enum { INITIALIZED_FALSE=0, INITIALIZED_TRUE=1 } InitializedOptions;
|
|
||||||
// Field AlgorithmSet information
|
// Field AlgorithmSet information
|
||||||
/* Enumeration options for field AlgorithmSet */
|
/* Enumeration options for field AlgorithmSet */
|
||||||
typedef enum { ALGORITHMSET_FALSE=0, ALGORITHMSET_TRUE=1 } AlgorithmSetOptions;
|
typedef enum { ALGORITHMSET_FALSE=0, ALGORITHMSET_TRUE=1 } AlgorithmSetOptions;
|
||||||
@ -81,10 +79,20 @@ public:
|
|||||||
// Field HomeSet information
|
// Field HomeSet information
|
||||||
/* Enumeration options for field HomeSet */
|
/* Enumeration options for field HomeSet */
|
||||||
typedef enum { HOMESET_FALSE=0, HOMESET_TRUE=1 } HomeSetOptions;
|
typedef enum { HOMESET_FALSE=0, HOMESET_TRUE=1 } HomeSetOptions;
|
||||||
|
// Field LinkRunning information
|
||||||
|
/* Enumeration options for field LinkRunning */
|
||||||
|
typedef enum { LINKRUNNING_FALSE=0, LINKRUNNING_TRUE=1 } LinkRunningOptions;
|
||||||
|
// Field AhrsKickstarts information
|
||||||
|
// Field AhrsCrcErrors information
|
||||||
|
// Field AhrsRetries information
|
||||||
|
// Field AhrsInvalidPackets information
|
||||||
|
// Field OpCrcErrors information
|
||||||
|
// Field OpRetries information
|
||||||
|
// Field OpInvalidPackets information
|
||||||
|
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
static const quint32 OBJID = 4061809000U;
|
static const quint32 OBJID = 188215176U;
|
||||||
static const QString NAME;
|
static const QString NAME;
|
||||||
static const bool ISSINGLEINST = 1;
|
static const bool ISSINGLEINST = 1;
|
||||||
static const bool ISSETTINGS = 0;
|
static const bool ISSETTINGS = 0;
|
||||||
|
@ -40,7 +40,7 @@ _fields = [ \
|
|||||||
uavobject.UAVObjectField(
|
uavobject.UAVObjectField(
|
||||||
'SerialNumber',
|
'SerialNumber',
|
||||||
'B',
|
'B',
|
||||||
25,
|
8,
|
||||||
[
|
[
|
||||||
'0',
|
'0',
|
||||||
'1',
|
'1',
|
||||||
@ -50,23 +50,6 @@ _fields = [ \
|
|||||||
'5',
|
'5',
|
||||||
'6',
|
'6',
|
||||||
'7',
|
'7',
|
||||||
'8',
|
|
||||||
'9',
|
|
||||||
'10',
|
|
||||||
'11',
|
|
||||||
'12',
|
|
||||||
'13',
|
|
||||||
'14',
|
|
||||||
'15',
|
|
||||||
'16',
|
|
||||||
'17',
|
|
||||||
'18',
|
|
||||||
'19',
|
|
||||||
'20',
|
|
||||||
'21',
|
|
||||||
'22',
|
|
||||||
'23',
|
|
||||||
'24',
|
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -111,32 +94,6 @@ _fields = [ \
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'CommErrors',
|
|
||||||
'B',
|
|
||||||
5,
|
|
||||||
[
|
|
||||||
'Algorithm',
|
|
||||||
'Update',
|
|
||||||
'AttitudeRaw',
|
|
||||||
'HomeLocation',
|
|
||||||
'Calibration',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
}
|
|
||||||
),
|
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'Initialized',
|
|
||||||
'b',
|
|
||||||
1,
|
|
||||||
[
|
|
||||||
'0',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
'0' : 'FALSE',
|
|
||||||
'1' : 'TRUE',
|
|
||||||
}
|
|
||||||
),
|
|
||||||
uavobject.UAVObjectField(
|
uavobject.UAVObjectField(
|
||||||
'AlgorithmSet',
|
'AlgorithmSet',
|
||||||
'b',
|
'b',
|
||||||
@ -173,12 +130,94 @@ _fields = [ \
|
|||||||
'1' : 'TRUE',
|
'1' : 'TRUE',
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
uavobject.UAVObjectField(
|
||||||
|
'LinkRunning',
|
||||||
|
'b',
|
||||||
|
1,
|
||||||
|
[
|
||||||
|
'0',
|
||||||
|
],
|
||||||
|
{
|
||||||
|
'0' : 'FALSE',
|
||||||
|
'1' : 'TRUE',
|
||||||
|
}
|
||||||
|
),
|
||||||
|
uavobject.UAVObjectField(
|
||||||
|
'AhrsKickstarts',
|
||||||
|
'B',
|
||||||
|
1,
|
||||||
|
[
|
||||||
|
'0',
|
||||||
|
],
|
||||||
|
{
|
||||||
|
}
|
||||||
|
),
|
||||||
|
uavobject.UAVObjectField(
|
||||||
|
'AhrsCrcErrors',
|
||||||
|
'B',
|
||||||
|
1,
|
||||||
|
[
|
||||||
|
'0',
|
||||||
|
],
|
||||||
|
{
|
||||||
|
}
|
||||||
|
),
|
||||||
|
uavobject.UAVObjectField(
|
||||||
|
'AhrsRetries',
|
||||||
|
'B',
|
||||||
|
1,
|
||||||
|
[
|
||||||
|
'0',
|
||||||
|
],
|
||||||
|
{
|
||||||
|
}
|
||||||
|
),
|
||||||
|
uavobject.UAVObjectField(
|
||||||
|
'AhrsInvalidPackets',
|
||||||
|
'B',
|
||||||
|
1,
|
||||||
|
[
|
||||||
|
'0',
|
||||||
|
],
|
||||||
|
{
|
||||||
|
}
|
||||||
|
),
|
||||||
|
uavobject.UAVObjectField(
|
||||||
|
'OpCrcErrors',
|
||||||
|
'B',
|
||||||
|
1,
|
||||||
|
[
|
||||||
|
'0',
|
||||||
|
],
|
||||||
|
{
|
||||||
|
}
|
||||||
|
),
|
||||||
|
uavobject.UAVObjectField(
|
||||||
|
'OpRetries',
|
||||||
|
'B',
|
||||||
|
1,
|
||||||
|
[
|
||||||
|
'0',
|
||||||
|
],
|
||||||
|
{
|
||||||
|
}
|
||||||
|
),
|
||||||
|
uavobject.UAVObjectField(
|
||||||
|
'OpInvalidPackets',
|
||||||
|
'B',
|
||||||
|
1,
|
||||||
|
[
|
||||||
|
'0',
|
||||||
|
],
|
||||||
|
{
|
||||||
|
}
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class AhrsStatus(uavobject.UAVObject):
|
class AhrsStatus(uavobject.UAVObject):
|
||||||
## Object constants
|
## Object constants
|
||||||
OBJID = 4061809000
|
OBJID = 188215176
|
||||||
NAME = "AhrsStatus"
|
NAME = "AhrsStatus"
|
||||||
METANAME = "AhrsStatusMeta"
|
METANAME = "AhrsStatusMeta"
|
||||||
ISSINGLEINST = 1
|
ISSINGLEINST = 1
|
||||||
|
@ -1,192 +0,0 @@
|
|||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
*
|
|
||||||
* @file ahrsstatus2.cpp
|
|
||||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
|
||||||
* @see The GNU Public License (GPL) Version 3
|
|
||||||
* @addtogroup GCSPlugins GCS Plugins
|
|
||||||
* @{
|
|
||||||
* @addtogroup UAVObjectsPlugin UAVObjects Plugin
|
|
||||||
* @{
|
|
||||||
*
|
|
||||||
* @note Object definition file: ahrsstatus2.xml.
|
|
||||||
* This is an automatically generated file.
|
|
||||||
* DO NOT modify manually.
|
|
||||||
*
|
|
||||||
* @brief The UAVUObjects GCS plugin
|
|
||||||
*****************************************************************************/
|
|
||||||
/*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#include "ahrsstatus2.h"
|
|
||||||
#include "uavobjectfield.h"
|
|
||||||
|
|
||||||
const QString AhrsStatus2::NAME = QString("AhrsStatus2");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
AhrsStatus2::AhrsStatus2(): UAVDataObject(OBJID, ISSINGLEINST, ISSETTINGS, NAME)
|
|
||||||
{
|
|
||||||
// Create fields
|
|
||||||
QList<UAVObjectField*> fields;
|
|
||||||
QStringList SerialNumberElemNames;
|
|
||||||
SerialNumberElemNames.append("0");
|
|
||||||
SerialNumberElemNames.append("1");
|
|
||||||
SerialNumberElemNames.append("2");
|
|
||||||
SerialNumberElemNames.append("3");
|
|
||||||
SerialNumberElemNames.append("4");
|
|
||||||
SerialNumberElemNames.append("5");
|
|
||||||
SerialNumberElemNames.append("6");
|
|
||||||
SerialNumberElemNames.append("7");
|
|
||||||
fields.append( new UAVObjectField(QString("SerialNumber"), QString("n/a"), UAVObjectField::UINT8, SerialNumberElemNames, QStringList()) );
|
|
||||||
QStringList CPULoadElemNames;
|
|
||||||
CPULoadElemNames.append("0");
|
|
||||||
fields.append( new UAVObjectField(QString("CPULoad"), QString("count"), UAVObjectField::UINT8, CPULoadElemNames, QStringList()) );
|
|
||||||
QStringList IdleTimePerCyleElemNames;
|
|
||||||
IdleTimePerCyleElemNames.append("0");
|
|
||||||
fields.append( new UAVObjectField(QString("IdleTimePerCyle"), QString("10x ms"), UAVObjectField::UINT8, IdleTimePerCyleElemNames, QStringList()) );
|
|
||||||
QStringList RunningTimePerCyleElemNames;
|
|
||||||
RunningTimePerCyleElemNames.append("0");
|
|
||||||
fields.append( new UAVObjectField(QString("RunningTimePerCyle"), QString("10x ms"), UAVObjectField::UINT8, RunningTimePerCyleElemNames, QStringList()) );
|
|
||||||
QStringList DroppedUpdatesElemNames;
|
|
||||||
DroppedUpdatesElemNames.append("0");
|
|
||||||
fields.append( new UAVObjectField(QString("DroppedUpdates"), QString("count"), UAVObjectField::UINT8, DroppedUpdatesElemNames, QStringList()) );
|
|
||||||
QStringList AlgorithmSetElemNames;
|
|
||||||
AlgorithmSetElemNames.append("0");
|
|
||||||
QStringList AlgorithmSetEnumOptions;
|
|
||||||
AlgorithmSetEnumOptions.append("FALSE");
|
|
||||||
AlgorithmSetEnumOptions.append("TRUE");
|
|
||||||
fields.append( new UAVObjectField(QString("AlgorithmSet"), QString(""), UAVObjectField::ENUM, AlgorithmSetElemNames, AlgorithmSetEnumOptions) );
|
|
||||||
QStringList CalibrationSetElemNames;
|
|
||||||
CalibrationSetElemNames.append("0");
|
|
||||||
QStringList CalibrationSetEnumOptions;
|
|
||||||
CalibrationSetEnumOptions.append("FALSE");
|
|
||||||
CalibrationSetEnumOptions.append("TRUE");
|
|
||||||
fields.append( new UAVObjectField(QString("CalibrationSet"), QString(""), UAVObjectField::ENUM, CalibrationSetElemNames, CalibrationSetEnumOptions) );
|
|
||||||
QStringList HomeSetElemNames;
|
|
||||||
HomeSetElemNames.append("0");
|
|
||||||
QStringList HomeSetEnumOptions;
|
|
||||||
HomeSetEnumOptions.append("FALSE");
|
|
||||||
HomeSetEnumOptions.append("TRUE");
|
|
||||||
fields.append( new UAVObjectField(QString("HomeSet"), QString(""), UAVObjectField::ENUM, HomeSetElemNames, HomeSetEnumOptions) );
|
|
||||||
QStringList LinkRunningElemNames;
|
|
||||||
LinkRunningElemNames.append("0");
|
|
||||||
QStringList LinkRunningEnumOptions;
|
|
||||||
LinkRunningEnumOptions.append("FALSE");
|
|
||||||
LinkRunningEnumOptions.append("TRUE");
|
|
||||||
fields.append( new UAVObjectField(QString("LinkRunning"), QString(""), UAVObjectField::ENUM, LinkRunningElemNames, LinkRunningEnumOptions) );
|
|
||||||
QStringList AhrsKickstartsElemNames;
|
|
||||||
AhrsKickstartsElemNames.append("0");
|
|
||||||
fields.append( new UAVObjectField(QString("AhrsKickstarts"), QString("count"), UAVObjectField::UINT8, AhrsKickstartsElemNames, QStringList()) );
|
|
||||||
QStringList AhrsCrcErrorsElemNames;
|
|
||||||
AhrsCrcErrorsElemNames.append("0");
|
|
||||||
fields.append( new UAVObjectField(QString("AhrsCrcErrors"), QString("count"), UAVObjectField::UINT8, AhrsCrcErrorsElemNames, QStringList()) );
|
|
||||||
QStringList AhrsRetriesElemNames;
|
|
||||||
AhrsRetriesElemNames.append("0");
|
|
||||||
fields.append( new UAVObjectField(QString("AhrsRetries"), QString("count"), UAVObjectField::UINT8, AhrsRetriesElemNames, QStringList()) );
|
|
||||||
QStringList AhrsInvalidPacketsElemNames;
|
|
||||||
AhrsInvalidPacketsElemNames.append("0");
|
|
||||||
fields.append( new UAVObjectField(QString("AhrsInvalidPackets"), QString("count"), UAVObjectField::UINT8, AhrsInvalidPacketsElemNames, QStringList()) );
|
|
||||||
QStringList OpCrcErrorsElemNames;
|
|
||||||
OpCrcErrorsElemNames.append("0");
|
|
||||||
fields.append( new UAVObjectField(QString("OpCrcErrors"), QString("count"), UAVObjectField::UINT8, OpCrcErrorsElemNames, QStringList()) );
|
|
||||||
QStringList OpRetriesElemNames;
|
|
||||||
OpRetriesElemNames.append("0");
|
|
||||||
fields.append( new UAVObjectField(QString("OpRetries"), QString("count"), UAVObjectField::UINT8, OpRetriesElemNames, QStringList()) );
|
|
||||||
QStringList OpInvalidPacketsElemNames;
|
|
||||||
OpInvalidPacketsElemNames.append("0");
|
|
||||||
fields.append( new UAVObjectField(QString("OpInvalidPackets"), QString("count"), UAVObjectField::UINT8, OpInvalidPacketsElemNames, QStringList()) );
|
|
||||||
|
|
||||||
// Initialize object
|
|
||||||
initializeFields(fields, (quint8*)&data, NUMBYTES);
|
|
||||||
// Set the default field values
|
|
||||||
setDefaultFieldValues();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the default metadata for this object
|
|
||||||
*/
|
|
||||||
UAVObject::Metadata AhrsStatus2::getDefaultMetadata()
|
|
||||||
{
|
|
||||||
UAVObject::Metadata metadata;
|
|
||||||
metadata.flightAccess = ACCESS_READWRITE;
|
|
||||||
metadata.gcsAccess = ACCESS_READWRITE;
|
|
||||||
metadata.gcsTelemetryAcked = 0;
|
|
||||||
metadata.gcsTelemetryUpdateMode = UAVObject::UPDATEMODE_MANUAL;
|
|
||||||
metadata.gcsTelemetryUpdatePeriod = 0;
|
|
||||||
metadata.flightTelemetryAcked = 0;
|
|
||||||
metadata.flightTelemetryUpdateMode = UAVObject::UPDATEMODE_PERIODIC;
|
|
||||||
metadata.flightTelemetryUpdatePeriod = 1000;
|
|
||||||
metadata.loggingUpdateMode = UAVObject::UPDATEMODE_PERIODIC;
|
|
||||||
metadata.loggingUpdatePeriod = 1000;
|
|
||||||
return metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize object fields with the default values.
|
|
||||||
* If a default value is not specified the object fields
|
|
||||||
* will be initialized to zero.
|
|
||||||
*/
|
|
||||||
void AhrsStatus2::setDefaultFieldValues()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the object data fields
|
|
||||||
*/
|
|
||||||
AhrsStatus2::DataFields AhrsStatus2::getData()
|
|
||||||
{
|
|
||||||
QMutexLocker locker(mutex);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the object data fields
|
|
||||||
*/
|
|
||||||
void AhrsStatus2::setData(const DataFields& data)
|
|
||||||
{
|
|
||||||
QMutexLocker locker(mutex);
|
|
||||||
// Get metadata
|
|
||||||
Metadata mdata = getMetadata();
|
|
||||||
// Update object if the access mode permits
|
|
||||||
if ( mdata.gcsAccess == ACCESS_READWRITE )
|
|
||||||
{
|
|
||||||
this->data = data;
|
|
||||||
emit objectUpdatedAuto(this); // trigger object updated event
|
|
||||||
emit objectUpdated(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a clone of this object, a new instance ID must be specified.
|
|
||||||
* Do not use this function directly to create new instances, the
|
|
||||||
* UAVObjectManager should be used instead.
|
|
||||||
*/
|
|
||||||
UAVDataObject* AhrsStatus2::clone(quint32 instID)
|
|
||||||
{
|
|
||||||
AhrsStatus2* obj = new AhrsStatus2();
|
|
||||||
obj->initialize(instID, this->getMetaObject());
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Static function to retrieve an instance of the object.
|
|
||||||
*/
|
|
||||||
AhrsStatus2* AhrsStatus2::GetInstance(UAVObjectManager* objMngr, quint32 instID)
|
|
||||||
{
|
|
||||||
return dynamic_cast<AhrsStatus2*>(objMngr->getObject(AhrsStatus2::OBJID, instID));
|
|
||||||
}
|
|
@ -1,118 +0,0 @@
|
|||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
*
|
|
||||||
* @file ahrsstatus2.h
|
|
||||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
|
||||||
* @see The GNU Public License (GPL) Version 3
|
|
||||||
* @addtogroup GCSPlugins GCS Plugins
|
|
||||||
* @{
|
|
||||||
* @addtogroup UAVObjectsPlugin UAVObjects Plugin
|
|
||||||
* @{
|
|
||||||
*
|
|
||||||
* @note Object definition file: ahrsstatus2.xml.
|
|
||||||
* This is an automatically generated file.
|
|
||||||
* DO NOT modify manually.
|
|
||||||
*
|
|
||||||
* @brief The UAVUObjects GCS plugin
|
|
||||||
*****************************************************************************/
|
|
||||||
/*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#ifndef AHRSSTATUS2_H
|
|
||||||
#define AHRSSTATUS2_H
|
|
||||||
|
|
||||||
#include "uavdataobject.h"
|
|
||||||
#include "uavobjectmanager.h"
|
|
||||||
|
|
||||||
class UAVOBJECTS_EXPORT AhrsStatus2: public UAVDataObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Field structure
|
|
||||||
typedef struct {
|
|
||||||
quint8 SerialNumber[8];
|
|
||||||
quint8 CPULoad;
|
|
||||||
quint8 IdleTimePerCyle;
|
|
||||||
quint8 RunningTimePerCyle;
|
|
||||||
quint8 DroppedUpdates;
|
|
||||||
quint8 AlgorithmSet;
|
|
||||||
quint8 CalibrationSet;
|
|
||||||
quint8 HomeSet;
|
|
||||||
quint8 LinkRunning;
|
|
||||||
quint8 AhrsKickstarts;
|
|
||||||
quint8 AhrsCrcErrors;
|
|
||||||
quint8 AhrsRetries;
|
|
||||||
quint8 AhrsInvalidPackets;
|
|
||||||
quint8 OpCrcErrors;
|
|
||||||
quint8 OpRetries;
|
|
||||||
quint8 OpInvalidPackets;
|
|
||||||
|
|
||||||
} __attribute__((packed)) DataFields;
|
|
||||||
|
|
||||||
// Field information
|
|
||||||
// Field SerialNumber information
|
|
||||||
/* Number of elements for field SerialNumber */
|
|
||||||
static const quint32 SERIALNUMBER_NUMELEM = 8;
|
|
||||||
// Field CPULoad information
|
|
||||||
// Field IdleTimePerCyle information
|
|
||||||
// Field RunningTimePerCyle information
|
|
||||||
// Field DroppedUpdates information
|
|
||||||
// Field AlgorithmSet information
|
|
||||||
/* Enumeration options for field AlgorithmSet */
|
|
||||||
typedef enum { ALGORITHMSET_FALSE=0, ALGORITHMSET_TRUE=1 } AlgorithmSetOptions;
|
|
||||||
// Field CalibrationSet information
|
|
||||||
/* Enumeration options for field CalibrationSet */
|
|
||||||
typedef enum { CALIBRATIONSET_FALSE=0, CALIBRATIONSET_TRUE=1 } CalibrationSetOptions;
|
|
||||||
// Field HomeSet information
|
|
||||||
/* Enumeration options for field HomeSet */
|
|
||||||
typedef enum { HOMESET_FALSE=0, HOMESET_TRUE=1 } HomeSetOptions;
|
|
||||||
// Field LinkRunning information
|
|
||||||
/* Enumeration options for field LinkRunning */
|
|
||||||
typedef enum { LINKRUNNING_FALSE=0, LINKRUNNING_TRUE=1 } LinkRunningOptions;
|
|
||||||
// Field AhrsKickstarts information
|
|
||||||
// Field AhrsCrcErrors information
|
|
||||||
// Field AhrsRetries information
|
|
||||||
// Field AhrsInvalidPackets information
|
|
||||||
// Field OpCrcErrors information
|
|
||||||
// Field OpRetries information
|
|
||||||
// Field OpInvalidPackets information
|
|
||||||
|
|
||||||
|
|
||||||
// Constants
|
|
||||||
static const quint32 OBJID = 805003662U;
|
|
||||||
static const QString NAME;
|
|
||||||
static const bool ISSINGLEINST = 1;
|
|
||||||
static const bool ISSETTINGS = 0;
|
|
||||||
static const quint32 NUMBYTES = sizeof(DataFields);
|
|
||||||
|
|
||||||
// Functions
|
|
||||||
AhrsStatus2();
|
|
||||||
|
|
||||||
DataFields getData();
|
|
||||||
void setData(const DataFields& data);
|
|
||||||
Metadata getDefaultMetadata();
|
|
||||||
UAVDataObject* clone(quint32 instID);
|
|
||||||
|
|
||||||
static AhrsStatus2* GetInstance(UAVObjectManager* objMngr, quint32 instID = 0);
|
|
||||||
|
|
||||||
private:
|
|
||||||
DataFields data;
|
|
||||||
|
|
||||||
void setDefaultFieldValues();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // AHRSSTATUS2_H
|
|
@ -1,251 +0,0 @@
|
|||||||
##
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# @file ahrsstatus2.py
|
|
||||||
# @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
|
||||||
# @brief Implementation of the AhrsStatus2 object. This file has been
|
|
||||||
# automatically generated by the UAVObjectGenerator.
|
|
||||||
#
|
|
||||||
# @note Object definition file: ahrsstatus2.xml.
|
|
||||||
# This is an automatically generated file.
|
|
||||||
# DO NOT modify manually.
|
|
||||||
#
|
|
||||||
# @see The GNU Public License (GPL) Version 3
|
|
||||||
#
|
|
||||||
#############################################################################/
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful, but
|
|
||||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
# for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along
|
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
import uavobject
|
|
||||||
|
|
||||||
import struct
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
# This is a list of instances of the data fields contained in this object
|
|
||||||
_fields = [ \
|
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'SerialNumber',
|
|
||||||
'B',
|
|
||||||
8,
|
|
||||||
[
|
|
||||||
'0',
|
|
||||||
'1',
|
|
||||||
'2',
|
|
||||||
'3',
|
|
||||||
'4',
|
|
||||||
'5',
|
|
||||||
'6',
|
|
||||||
'7',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
}
|
|
||||||
),
|
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'CPULoad',
|
|
||||||
'B',
|
|
||||||
1,
|
|
||||||
[
|
|
||||||
'0',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
}
|
|
||||||
),
|
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'IdleTimePerCyle',
|
|
||||||
'B',
|
|
||||||
1,
|
|
||||||
[
|
|
||||||
'0',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
}
|
|
||||||
),
|
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'RunningTimePerCyle',
|
|
||||||
'B',
|
|
||||||
1,
|
|
||||||
[
|
|
||||||
'0',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
}
|
|
||||||
),
|
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'DroppedUpdates',
|
|
||||||
'B',
|
|
||||||
1,
|
|
||||||
[
|
|
||||||
'0',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
}
|
|
||||||
),
|
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'AlgorithmSet',
|
|
||||||
'b',
|
|
||||||
1,
|
|
||||||
[
|
|
||||||
'0',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
'0' : 'FALSE',
|
|
||||||
'1' : 'TRUE',
|
|
||||||
}
|
|
||||||
),
|
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'CalibrationSet',
|
|
||||||
'b',
|
|
||||||
1,
|
|
||||||
[
|
|
||||||
'0',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
'0' : 'FALSE',
|
|
||||||
'1' : 'TRUE',
|
|
||||||
}
|
|
||||||
),
|
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'HomeSet',
|
|
||||||
'b',
|
|
||||||
1,
|
|
||||||
[
|
|
||||||
'0',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
'0' : 'FALSE',
|
|
||||||
'1' : 'TRUE',
|
|
||||||
}
|
|
||||||
),
|
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'LinkRunning',
|
|
||||||
'b',
|
|
||||||
1,
|
|
||||||
[
|
|
||||||
'0',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
'0' : 'FALSE',
|
|
||||||
'1' : 'TRUE',
|
|
||||||
}
|
|
||||||
),
|
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'AhrsKickstarts',
|
|
||||||
'B',
|
|
||||||
1,
|
|
||||||
[
|
|
||||||
'0',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
}
|
|
||||||
),
|
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'AhrsCrcErrors',
|
|
||||||
'B',
|
|
||||||
1,
|
|
||||||
[
|
|
||||||
'0',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
}
|
|
||||||
),
|
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'AhrsRetries',
|
|
||||||
'B',
|
|
||||||
1,
|
|
||||||
[
|
|
||||||
'0',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
}
|
|
||||||
),
|
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'AhrsInvalidPackets',
|
|
||||||
'B',
|
|
||||||
1,
|
|
||||||
[
|
|
||||||
'0',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
}
|
|
||||||
),
|
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'OpCrcErrors',
|
|
||||||
'B',
|
|
||||||
1,
|
|
||||||
[
|
|
||||||
'0',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
}
|
|
||||||
),
|
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'OpRetries',
|
|
||||||
'B',
|
|
||||||
1,
|
|
||||||
[
|
|
||||||
'0',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
}
|
|
||||||
),
|
|
||||||
uavobject.UAVObjectField(
|
|
||||||
'OpInvalidPackets',
|
|
||||||
'B',
|
|
||||||
1,
|
|
||||||
[
|
|
||||||
'0',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
}
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class AhrsStatus2(uavobject.UAVObject):
|
|
||||||
## Object constants
|
|
||||||
OBJID = 805003662
|
|
||||||
NAME = "AhrsStatus2"
|
|
||||||
METANAME = "AhrsStatus2Meta"
|
|
||||||
ISSINGLEINST = 1
|
|
||||||
ISSETTINGS = 0
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
uavobject.UAVObject.__init__(self,
|
|
||||||
self.OBJID,
|
|
||||||
self.NAME,
|
|
||||||
self.METANAME,
|
|
||||||
0,
|
|
||||||
self.ISSINGLEINST)
|
|
||||||
|
|
||||||
for f in _fields:
|
|
||||||
self.add_field(f)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
s = ("0x%08X (%10u) %-30s %3u bytes format '%s'\n"
|
|
||||||
% (self.OBJID, self.OBJID, self.NAME, self.get_struct().size, self.get_struct().format))
|
|
||||||
for f in self.get_tuple()._fields:
|
|
||||||
s += ("\t%s\n" % f)
|
|
||||||
return (s)
|
|
||||||
|
|
||||||
def main():
|
|
||||||
# Instantiate the object and dump out some interesting info
|
|
||||||
x = AhrsStatus2()
|
|
||||||
print (x)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
#import pdb ; pdb.run('main()')
|
|
||||||
main()
|
|
@ -48,8 +48,7 @@ HEADERS += uavobjects_global.h \
|
|||||||
velocityactual.h \
|
velocityactual.h \
|
||||||
guidancesettings.h \
|
guidancesettings.h \
|
||||||
positiondesired.h \
|
positiondesired.h \
|
||||||
attitudesettings.h \
|
attitudesettings.h
|
||||||
ahrsstatus2.h
|
|
||||||
|
|
||||||
SOURCES += uavobject.cpp \
|
SOURCES += uavobject.cpp \
|
||||||
uavmetaobject.cpp \
|
uavmetaobject.cpp \
|
||||||
@ -95,6 +94,5 @@ SOURCES += uavobject.cpp \
|
|||||||
velocityactual.cpp \
|
velocityactual.cpp \
|
||||||
guidancesettings.cpp \
|
guidancesettings.cpp \
|
||||||
positiondesired.cpp \
|
positiondesired.cpp \
|
||||||
attitudesettings.cpp \
|
attitudesettings.cpp
|
||||||
ahrsstatus2.cpp
|
|
||||||
OTHER_FILES += UAVObjects.pluginspec
|
OTHER_FILES += UAVObjects.pluginspec
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
#include "ahrscalibration.h"
|
#include "ahrscalibration.h"
|
||||||
#include "ahrssettings.h"
|
#include "ahrssettings.h"
|
||||||
#include "ahrsstatus.h"
|
#include "ahrsstatus.h"
|
||||||
#include "ahrsstatus2.h"
|
|
||||||
#include "attitudeactual.h"
|
#include "attitudeactual.h"
|
||||||
#include "attitudedesired.h"
|
#include "attitudedesired.h"
|
||||||
#include "attituderaw.h"
|
#include "attituderaw.h"
|
||||||
@ -83,7 +82,6 @@ void UAVObjectsInitialize(UAVObjectManager* objMngr)
|
|||||||
objMngr->registerObject( new AHRSCalibration() );
|
objMngr->registerObject( new AHRSCalibration() );
|
||||||
objMngr->registerObject( new AHRSSettings() );
|
objMngr->registerObject( new AHRSSettings() );
|
||||||
objMngr->registerObject( new AhrsStatus() );
|
objMngr->registerObject( new AhrsStatus() );
|
||||||
objMngr->registerObject( new AhrsStatus2() );
|
|
||||||
objMngr->registerObject( new AttitudeActual() );
|
objMngr->registerObject( new AttitudeActual() );
|
||||||
objMngr->registerObject( new AttitudeDesired() );
|
objMngr->registerObject( new AttitudeDesired() );
|
||||||
objMngr->registerObject( new AttitudeRaw() );
|
objMngr->registerObject( new AttitudeRaw() );
|
||||||
|
@ -1,16 +1,24 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<object name="AhrsStatus" singleinstance="true" settings="false">
|
<object name="AhrsStatus" singleinstance="true" settings="false">
|
||||||
<description>Status for the @ref AHRSCommsModule, including communication errors</description>
|
<description>Status for the @ref AHRSCommsModule, including communication errors</description>
|
||||||
<field name="SerialNumber" units="n/a" type="uint8" elements="25"/>
|
<field name="SerialNumber" units="n/a" type="uint8" elements="8"/>
|
||||||
<field name="CPULoad" units="count" type="uint8" elements="1"/>
|
<field name="CPULoad" units="count" type="uint8" elements="1"/>
|
||||||
<field name="IdleTimePerCyle" units="10x ms" type="uint8" elements="1"/>
|
<field name="IdleTimePerCyle" units="10x ms" type="uint8" elements="1"/>
|
||||||
<field name="RunningTimePerCyle" units="10x ms" type="uint8" elements="1"/>
|
<field name="RunningTimePerCyle" units="10x ms" type="uint8" elements="1"/>
|
||||||
<field name="DroppedUpdates" units="count" type="uint8" elements="1"/>
|
<field name="DroppedUpdates" units="count" type="uint8" elements="1"/>
|
||||||
<field name="CommErrors" units="count" type="uint8" elementnames="Algorithm,Update,AttitudeRaw,HomeLocation,Calibration"/>
|
|
||||||
<field name="Initialized" units="" type="enum" elements="1" options="FALSE,TRUE"/>
|
|
||||||
<field name="AlgorithmSet" units="" type="enum" elements="1" options="FALSE,TRUE"/>
|
<field name="AlgorithmSet" units="" type="enum" elements="1" options="FALSE,TRUE"/>
|
||||||
<field name="CalibrationSet" units="" type="enum" elements="1" options="FALSE,TRUE"/>
|
<field name="CalibrationSet" units="" type="enum" elements="1" options="FALSE,TRUE"/>
|
||||||
<field name="HomeSet" units="" type="enum" elements="1" options="FALSE,TRUE"/>
|
<field name="HomeSet" units="" type="enum" elements="1" options="FALSE,TRUE"/>
|
||||||
|
|
||||||
|
<field name="LinkRunning" units="" type="enum" elements="1" options="FALSE,TRUE"/>
|
||||||
|
<field name="AhrsKickstarts" units="count" type="uint8" elements="1"/>
|
||||||
|
<field name="AhrsCrcErrors" units="count" type="uint8" elements="1"/>
|
||||||
|
<field name="AhrsRetries" units="count" type="uint8" elements="1"/>
|
||||||
|
<field name="AhrsInvalidPackets" units="count" type="uint8" elements="1"/>
|
||||||
|
<field name="OpCrcErrors" units="count" type="uint8" elements="1"/>
|
||||||
|
<field name="OpRetries" units="count" type="uint8" elements="1"/>
|
||||||
|
<field name="OpInvalidPackets" units="count" type="uint8" elements="1"/>
|
||||||
|
|
||||||
<access gcs="readwrite" flight="readwrite"/>
|
<access gcs="readwrite" flight="readwrite"/>
|
||||||
<telemetrygcs acked="false" updatemode="manual" period="0"/>
|
<telemetrygcs acked="false" updatemode="manual" period="0"/>
|
||||||
<telemetryflight acked="false" updatemode="periodic" period="1000"/>
|
<telemetryflight acked="false" updatemode="periodic" period="1000"/>
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
<xml>
|
|
||||||
<object name="AhrsStatus2" singleinstance="true" settings="false">
|
|
||||||
<description>Status for the @ref AHRSCommsModule, including communication errors</description>
|
|
||||||
<field name="SerialNumber" units="n/a" type="uint8" elements="8"/>
|
|
||||||
<field name="CPULoad" units="count" type="uint8" elements="1"/>
|
|
||||||
<field name="IdleTimePerCyle" units="10x ms" type="uint8" elements="1"/>
|
|
||||||
<field name="RunningTimePerCyle" units="10x ms" type="uint8" elements="1"/>
|
|
||||||
<field name="DroppedUpdates" units="count" type="uint8" elements="1"/>
|
|
||||||
<field name="AlgorithmSet" units="" type="enum" elements="1" options="FALSE,TRUE"/>
|
|
||||||
<field name="CalibrationSet" units="" type="enum" elements="1" options="FALSE,TRUE"/>
|
|
||||||
<field name="HomeSet" units="" type="enum" elements="1" options="FALSE,TRUE"/>
|
|
||||||
|
|
||||||
<field name="LinkRunning" units="" type="enum" elements="1" options="FALSE,TRUE"/>
|
|
||||||
<field name="AhrsKickstarts" units="count" type="uint8" elements="1"/>
|
|
||||||
<field name="AhrsCrcErrors" units="count" type="uint8" elements="1"/>
|
|
||||||
<field name="AhrsRetries" units="count" type="uint8" elements="1"/>
|
|
||||||
<field name="AhrsInvalidPackets" units="count" type="uint8" elements="1"/>
|
|
||||||
<field name="OpCrcErrors" units="count" type="uint8" elements="1"/>
|
|
||||||
<field name="OpRetries" units="count" type="uint8" elements="1"/>
|
|
||||||
<field name="OpInvalidPackets" units="count" type="uint8" elements="1"/>
|
|
||||||
|
|
||||||
<access gcs="readwrite" flight="readwrite"/>
|
|
||||||
<telemetrygcs acked="false" updatemode="manual" period="0"/>
|
|
||||||
<telemetryflight acked="false" updatemode="periodic" period="1000"/>
|
|
||||||
<logging updatemode="periodic" period="1000"/>
|
|
||||||
</object>
|
|
||||||
</xml>
|
|
Loading…
Reference in New Issue
Block a user