diff --git a/conf/boards/bebop.makefile b/conf/boards/bebop.makefile index 6f00e27cff..6d9b714bd8 100644 --- a/conf/boards/bebop.makefile +++ b/conf/boards/bebop.makefile @@ -29,7 +29,7 @@ GPS_PORT ?= UART1 GPS_BAUD ?= B230400 # handle linux signals by hand -$(TARGET).CFLAGS += -DUSE_LINUX_SIGNAL +$(TARGET).CFLAGS += -DUSE_LINUX_SIGNAL -D_GNU_SOURCE # Compile the video specific parts $(TARGET).srcs += $(SRC_BOARD)/video.c diff --git a/conf/firmwares/rotorcraft.makefile b/conf/firmwares/rotorcraft.makefile index 9b6857bf81..0043002910 100644 --- a/conf/firmwares/rotorcraft.makefile +++ b/conf/firmwares/rotorcraft.makefile @@ -121,9 +121,9 @@ $(TARGET).srcs += $(SRC_ARCH)/mcu_periph/i2c_arch.c # # Electrical subsystem / Analog Backend # -ifneq ($(ARCH), linux) $(TARGET).CFLAGS += -DUSE_ADC $(TARGET).srcs += $(SRC_ARCH)/mcu_periph/adc_arch.c +ifneq ($(ARCH), linux) $(TARGET).srcs += subsystems/electrical.c endif diff --git a/conf/modules/sonar_bebop.xml b/conf/modules/sonar_bebop.xml new file mode 100644 index 0000000000..754f9d1bbe --- /dev/null +++ b/conf/modules/sonar_bebop.xml @@ -0,0 +1,31 @@ + + + + + + Bebop Sonar driver. + Reads an anlog sonar sensor and outputs sonar distance in [m] + + + + +
+ +
+ + + + + + + + + + + + + include $(CFG_SHARED)/spi_master.makefile + + + +
diff --git a/sw/airborne/arch/linux/mcu_periph/adc_arch.c b/sw/airborne/arch/linux/mcu_periph/adc_arch.c new file mode 100644 index 0000000000..8407379f00 --- /dev/null +++ b/sw/airborne/arch/linux/mcu_periph/adc_arch.c @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2015 Freek van Tienen + * + * This file is part of paparazzi. + * + * paparazzi 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 2, or (at your option) + * any later version. + * + * paparazzi 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 paparazzi; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * @file arch/linux/mcu_periph/adc_arch.c + * @ingroup linux_arch + * + * Driver for the analog to digital converters in Linux based systems. + */ + +#include "mcu_periph/adc.h" + +#include BOARD_CONFIG +#include +#include +#include +#include +#include +#include +#include + + +/******************************/ +/*** INTERNAL VARIABLES ***/ +/******************************/ + +/* ADC0 */ +#if USE_ADC0 +static uint8_t adc0_channels[] = {ADC0_CHANNELS}; +struct adc_t adc0 = { + .dev_id = ADC0_ID, + .channels = adc0_channels, + .channels_cnt = ADC0_CHANNELS_CNT, + .buf_length = ADC0_BUF_LENGTH +}; +#endif + +/* ADC1 */ +#if USE_ADC1 +static uint8_t adc1_channels[] = {ADC1_CHANNELS}; +struct adc_t adc1 = { + .dev_id = ADC1_ID, + .channels = adc1_channels, + .channels_cnt = ADC1_CHANNELS_CNT, + .buf_length = ADC1_BUF_LENGTH +}; +#endif + +/* Private functions */ +static inline void adc_dev_init(struct adc_t *adc); +static void write_sysfs_int(uint8_t dev_id, char *filename, int val); + +/***************************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***************************************/ + +/** + * Initialize the ADC + */ +void adc_init(void) +{ +#if USE_ADC0 + adc_dev_init(&adc0); +#endif +#if USE_ADC1 + adc_dev_init(&adc1); +#endif +} + +/** + * @todo: fx a more general ADC + */ +void adc_buf_channel(uint8_t adc_channel, struct adc_buf *s, uint8_t av_nb_sample) +{ + +} + +/** + * Start or stop the ADC readings + * @param[in] *adc The ADC to start the readings for + * @param[in] value 1 to enable and 0 to disable + */ +void adc_enable(struct adc_t *adc, uint8_t value) +{ + /* Write 1 or 0 to enable/disable the ADC */ + write_sysfs_int(adc->dev_id, "buffer/enable", value); +} + +/** + * Read the ADC buffer from the driver + * @param[in] *adc The adc you want to read from + * @param[out] *buf Output values + * @param[in] size The amount of bytes you want to read + */ +int adc_read(struct adc_t *adc, uint16_t *buf, uint16_t size) +{ + /* Allocate dev_id + name */ + char *temp; + if(asprintf(&temp, "/dev/iio:device%d", adc->dev_id) < 0) { + return -1; + } + + /* Open the file */ + int fd = open(temp, O_RDONLY | O_NONBLOCK); + free(temp); + + if(fd < 0) { + return -2; + } + + struct pollfd pfd; + pfd.fd = fd; + pfd.events = POLLIN; + poll(&pfd, 1, -1); + + /* Read the file */ + int ret = read(fd, buf, size); + close(fd); + return ret; +} + +/****************************************/ +/*** PRIVATE FUNCTION DEFINITIONS ***/ +/****************************************/ + +/** + * Initialize an ADC device + * @param[in] *adc The ADC device to initialize + */ +static inline void adc_dev_init(struct adc_t *adc) +{ + char filename[32]; + uint8_t i; + + /* Enable all linked channels */ + for(i = 0; i < adc->channels_cnt; i++) { + sprintf(filename, "scan_elemens/in_voltage%d_en", adc->channels[i]); + write_sysfs_int(adc->dev_id, filename, 1); + } + + /* Set the buffer length */ + write_sysfs_int(adc->dev_id, "buffer/length", adc->buf_length); +} + +/** + * Write an int to a sysfs file + * @param[in] dev_id The device id + * @param[in] *filename The file to write to + * @param[in] val The value to write + */ +static void write_sysfs_int(uint8_t dev_id, char *filename, int val) +{ + /* Allocate dev_id + filename */ + char *temp; + if (asprintf(&temp, "/sys/bus/iio/devices/iio:device%d/%s", dev_id, filename) < 0) { + return; + } + + /* Open the file */ + FILE *fd = fopen(temp, "w"); + free(temp); + + if (fd == NULL) { + return; + } + + /* Write the value to the file */ + fprintf(fd, "%d", val); + fclose(fd); +} diff --git a/sw/airborne/arch/linux/mcu_periph/adc_arch.h b/sw/airborne/arch/linux/mcu_periph/adc_arch.h new file mode 100644 index 0000000000..824dfb4c29 --- /dev/null +++ b/sw/airborne/arch/linux/mcu_periph/adc_arch.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 Freek van Tienen + * + * This file is part of Paparazzi. + * + * Paparazzi 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 2, or (at your option) + * any later version. + * + * Paparazzi 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 Paparazzi; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/** + * @file arch/linux/mcu_periph/adc_arch.h + * @ingroup linux_arch + * + * Driver for the analog to digital converters in Linux based systems.. + */ + +#ifndef ADC_ARCH_H +#define ADC_ARCH_H + +/* Main ADC structure */ +struct adc_t { + uint8_t dev_id; ///< The iio device ID + uint8_t *channels; ///< Channels used in the iio device + uint8_t channels_cnt; ///< Amount of channels + uint16_t buf_length; ///< ADC buffer length +}; + +#if USE_ADC0 +extern struct adc_t adc0; +#endif + +#if USE_ADC1 +extern struct adc_t adc1; +#endif + +void adc_enable(struct adc_t *adc, uint8_t value); +int adc_read(struct adc_t *adc, uint16_t *buf, uint16_t size); + +#endif /* ADC_ARCH_H */ diff --git a/sw/airborne/arch/linux/mcu_periph/spi_arch.c b/sw/airborne/arch/linux/mcu_periph/spi_arch.c index e4d6446f5f..1fe3dd0927 100644 --- a/sw/airborne/arch/linux/mcu_periph/spi_arch.c +++ b/sw/airborne/arch/linux/mcu_periph/spi_arch.c @@ -33,6 +33,7 @@ #include #include "mcu_periph/spi.h" +#include BOARD_CONFIG void spi_init_slaves(void) @@ -42,6 +43,8 @@ void spi_init_slaves(void) */ } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" bool_t spi_submit(struct spi_periph *p, struct spi_transaction *t) { int fd = (int)p->reg_addr; @@ -73,7 +76,7 @@ bool_t spi_submit(struct spi_periph *p, struct spi_transaction *t) xfer.len = buf_len; /* fixed speed of 1Mhz for now, use SPIClockDiv?? */ - xfer.speed_hz = 1000000; + xfer.speed_hz = (uint32_t)p->init_struct; xfer.delay_usecs = 0; if (t->dss == SPIDss16bit) { xfer.bits_per_word = 16; @@ -84,19 +87,20 @@ bool_t spi_submit(struct spi_periph *p, struct spi_transaction *t) xfer.cs_change = 1; } - if (ioctl(fd, SPI_IOC_MESSAGE(1), xfer) < 0) { + if (ioctl(fd, SPI_IOC_MESSAGE(1), &xfer) < 0) { t->status = SPITransFailed; return FALSE; } /* copy recieved data if we had to use an extra rx_buffer */ if (buf_len > t->input_length) { - memcpy((void *)t->input_buf, (void *)xfer.rx_buf, t->input_length); + memcpy((void *)t->input_buf, (void *)((uint32_t)xfer.rx_buf), t->input_length); } t->status = SPITransSuccess; return TRUE; } +#pragma GCC diagnostic pop bool_t spi_lock(struct spi_periph *p, uint8_t slave) { @@ -112,6 +116,23 @@ bool_t spi_resume(struct spi_periph *p, uint8_t slave) #if USE_SPI0 + +#ifndef SPI0_MODE +#define SPI0_MODE (SPI_CPOL | SPI_CPHA) +#endif + +#ifndef SPI0_LSB_FIRST +#define SPI0_LSB_FIRST 0 +#endif + +#ifndef SPI0_BITS_PER_WORD +#define SPI0_BITS_PER_WORD 8 +#endif + +#ifndef SPI0_MAX_SPEED_HZ +#define SPI0_MAX_SPEED_HZ 1000000 +#endif + void spi0_arch_init(void) { int fd = open("/dev/spidev1.0", O_RDWR); @@ -124,32 +145,50 @@ void spi0_arch_init(void) spi0.reg_addr = (void *)fd; /* spi mode */ - unsigned char spi_mode = (SPI_CPOL | SPI_CPHA); + unsigned char spi_mode = SPI0_MODE; if (ioctl(fd, SPI_IOC_WR_MODE, &spi_mode) < 0) { perror("SPI0: can't set spi mode"); } /* set to MSB first */ - unsigned char spi_order = 0; + unsigned char spi_order = SPI0_LSB_FIRST; if (ioctl(fd, SPI_IOC_WR_LSB_FIRST, &spi_order) < 0) { perror("SPI0: can't set spi bit justification"); } /* bits per word default to 8 */ - unsigned char spi_bits_per_word = 8; + unsigned char spi_bits_per_word = SPI0_BITS_PER_WORD; if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits_per_word) < 0) { perror("SPI0: can't set bits per word"); } /* max speed in hz, 1MHz for now */ - unsigned int spi_speed = 1000000; + unsigned int spi_speed = SPI0_MAX_SPEED_HZ; if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed) < 0) { perror("SPI0: can't set max speed hz"); } + spi0.init_struct = (void *)SPI0_MAX_SPEED_HZ; } #endif /* USE_SPI0 */ #if USE_SPI1 + +#ifndef SPI1_MODE +#define SPI1_MODE (SPI_CPOL | SPI_CPHA) +#endif + +#ifndef SPI1_LSB_FIRST +#define SPI1_LSB_FIRST 0 +#endif + +#ifndef SPI1_BITS_PER_WORD +#define SPI1_BITS_PER_WORD 8 +#endif + +#ifndef SPI1_MAX_SPEED_HZ +#define SPI1_MAX_SPEED_HZ 1000000 +#endif + void spi1_arch_init(void) { int fd = open("/dev/spidev1.1", O_RDWR); @@ -162,27 +201,28 @@ void spi1_arch_init(void) spi1.reg_addr = (void *)fd; /* spi mode */ - unsigned char spi_mode = (SPI_CPOL | SPI_CPHA); + unsigned char spi_mode = SPI1_MODE; if (ioctl(fd, SPI_IOC_WR_MODE, &spi_mode) < 0) { perror("SPI1: can't set spi mode"); } /* set to MSB first */ - unsigned char spi_order = 0; + unsigned char spi_order = SPI1_LSB_FIRST; if (ioctl(fd, SPI_IOC_WR_LSB_FIRST, &spi_order) < 0) { perror("SPI1: can't set spi bit justification"); } /* bits per word default to 8 */ - unsigned char spi_bits_per_word = 8; - if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits_per_word) < 0) { + unsigned char spi_bits_per_word = SPI1_BITS_PER_WORD; + if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits_per_word) < 0) {r perror("SPI1: can't set bits per word"); } /* max speed in hz, 1MHz for now */ - unsigned int spi_speed = 1000000; + unsigned int spi_speed = SPI1_MAX_SPEED_HZ; if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed) < 0) { perror("SPI1: can't set max speed hz"); } + spi1.init_struct = (void *)SPI1_MAX_SPEED_HZ; } #endif /* USE_SPI1 */ diff --git a/sw/airborne/boards/bebop.h b/sw/airborne/boards/bebop.h index 340585df4f..45b72faf7b 100644 --- a/sw/airborne/boards/bebop.h +++ b/sw/airborne/boards/bebop.h @@ -40,4 +40,19 @@ #define USE_BARO_BOARD 1 #endif +/* The ADC from the sonar */ +#if USE_ADC0 +#define ADC0_ID 0 +#define ADC0_CHANNELS 2 +#define ADC0_CHANNELS_CNT 1 +#define ADC0_BUF_LENGTH 8192 +#endif + +/* The SPI from the sonar */ +#if USE_SPI0 +#define SPI0_MODE 0 +#define SPI0_BITS_PER_WORD 8 +#define SPI0_MAX_SPEED_HZ 320000 +#endif + #endif /* CONFIG_BEBOP */ diff --git a/sw/airborne/math/pprz_algebra_float.c b/sw/airborne/math/pprz_algebra_float.c index ff978ca0a2..66dbf16050 100644 --- a/sw/airborne/math/pprz_algebra_float.c +++ b/sw/airborne/math/pprz_algebra_float.c @@ -398,7 +398,7 @@ void float_quat_integrate(struct FloatQuat *q, struct FloatRates *omega, float d } } -void float_quat_vmult(struct FloatVect3 *v_out, struct FloatQuat *q, struct FloatVect3 *v_in) +void float_quat_vmult(struct FloatVect3 *v_out, struct FloatQuat *q, const struct FloatVect3 *v_in) { const float qi2_M1_2 = q->qi * q->qi - 0.5; const float qiqx = q->qi * q->qx; diff --git a/sw/airborne/math/pprz_algebra_float.h b/sw/airborne/math/pprz_algebra_float.h index 3e9b940357..4e3a0fa9ae 100644 --- a/sw/airborne/math/pprz_algebra_float.h +++ b/sw/airborne/math/pprz_algebra_float.h @@ -433,7 +433,7 @@ extern void float_quat_integrate(struct FloatQuat *q, struct FloatRates *omega, /** rotate 3D vector by quaternion. * vb = q_a2b * va * q_a2b^-1 */ -extern void float_quat_vmult(struct FloatVect3 *v_out, struct FloatQuat *q, struct FloatVect3 *v_in); +extern void float_quat_vmult(struct FloatVect3 *v_out, struct FloatQuat *q, const struct FloatVect3 *v_in); /// Quaternion from Euler angles. extern void float_quat_of_eulers(struct FloatQuat *q, struct FloatEulers *e); diff --git a/sw/airborne/modules/sonar/sonar_bebop.c b/sw/airborne/modules/sonar/sonar_bebop.c new file mode 100644 index 0000000000..3fb122498e --- /dev/null +++ b/sw/airborne/modules/sonar/sonar_bebop.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2015 Freek van Tienen + * + * This file is part of paparazzi. + * + * paparazzi 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 2, or (at your option) + * any later version. + * + * paparazzi 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 paparazzi; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/** @file modules/sonar/sonar_bebop.c + * @brief Parrot Bebop Sonar driver + */ + +#include "sonar_bebop.h" +#include "generated/airframe.h" +#include "mcu_periph/adc.h" +#include "mcu_periph/spi.h" +#include "subsystems/abi.h" +#include +#include "subsystems/datalink/downlink.h" + +#ifdef SITL +#include "state.h" +#endif + + +struct SonarBebop sonar_bebop; +static uint8_t sonar_bebop_spi_d[16] = { 0xF0,0xF0,0xF0,0xF0,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; +static struct spi_transaction sonar_bebop_spi_t; +static pthread_t sonar_bebop_thread; +static void *sonar_bebop_read(void *data); + +void sonar_bebop_init(void) +{ + sonar_bebop.meas = 0; + sonar_bebop.offset = 0; + + sonar_bebop_spi_t.status = SPITransDone; + sonar_bebop_spi_t.select = SPISelectUnselect; + sonar_bebop_spi_t.dss = SPIDss8bit; + sonar_bebop_spi_t.output_buf = sonar_bebop_spi_d; + sonar_bebop_spi_t.output_length = 16; + sonar_bebop_spi_t.input_buf = NULL; + sonar_bebop_spi_t.input_length = 0; + + int rc = pthread_create(&sonar_bebop_thread, NULL, sonar_bebop_read, NULL); + if (rc < 0) { + return; + } +} + +/** + * Read ADC value to update sonar measurement + */ +static void *sonar_bebop_read(void *data __attribute__((unused))) +{ + while(true) { + +#ifndef SITL + uint16_t i; + uint16_t adc_buffer[8192]; + + + /* Start ADC and send sonar output */ + adc_enable(&adc0, 1); + sonar_bebop_spi_t.status = SPITransDone; + spi_submit(&spi0, &sonar_bebop_spi_t); + while(sonar_bebop_spi_t.status != SPITransSuccess); + adc_read(&adc0, adc_buffer, 8192); + adc_enable(&adc0, 0); + + /* Find the peeks */ + uint16_t start_send = 0; + uint16_t stop_send = 0; + uint16_t first_peek = 0; + uint16_t lowest_value = 4095; + for(i = 0; i < 8192; i++){ + uint16_t adc_val = adc_buffer[i]>>4; + if(start_send == 0 && adc_val == 4095) + start_send = i; + else if(start_send != 0 && stop_send == 0 && adc_val != 4095) + { + stop_send = i-1; + i += 300; + continue; + } + + if(start_send != 0 && stop_send != 0 && first_peek == 0 && adc_val < lowest_value) + lowest_value = adc_val; + else if (start_send != 0 && stop_send != 0 && adc_val > lowest_value + 100) { + first_peek = i; + lowest_value = adc_val - 100; + } + else if(start_send != 0 && stop_send != 0 && first_peek != 0 && adc_val+100 < (adc_buffer[first_peek]>>4)) { + break; + } + } + + /* Calculate the distance from the peeks */ + uint16_t diff = stop_send - start_send; + int16_t peek_distance = first_peek - (stop_send - diff/2); + if(first_peek <= stop_send || diff > 250) + peek_distance = 0; + + sonar_bebop.distance = peek_distance / 1000.0; +#else // SITL + sonar_bebop.distance = stateGetPositionEnu_f()->z; + Bound(sonar_bebop.distance, 0.1f, 7.0f); + uint16_t peek_distance = 1; +#endif // SITL + + usleep(10000); + + if(peek_distance > 0) + { + // Send ABI message + AbiSendMsgAGL(AGL_SONAR_ADC_ID, sonar_bebop.distance); + +#ifdef SENSOR_SYNC_SEND_SONAR + // Send Telemetry report + DOWNLINK_SEND_SONAR(DefaultChannel, DefaultDevice, &sonar_bebop.meas, &sonar_bebop.distance); +#endif + } + } + + return NULL; +} + diff --git a/sw/airborne/modules/sonar/sonar_bebop.h b/sw/airborne/modules/sonar/sonar_bebop.h new file mode 100644 index 0000000000..5d3752354b --- /dev/null +++ b/sw/airborne/modules/sonar/sonar_bebop.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2015 Freek van Tienen + * + * This file is part of paparazzi. + * + * paparazzi 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 2, or (at your option) + * any later version. + * + * paparazzi 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 paparazzi; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/** @file modules/sonar/sonar_bebop.h + * @brief Parrot Bebop Sonar driver + */ + +#ifndef SONAR_BEBOP_H +#define SONAR_BEBOP_H + +#include "std.h" + +struct SonarBebop { + uint16_t meas; ///< Raw ADC value + uint16_t offset; ///< Sonar offset in ADC units + float distance; ///< Distance measured in meters +}; + +extern struct SonarBebop sonar_bebop; + +extern void sonar_bebop_init(void); + +#endif /* SONAR_BEBOP_H */ diff --git a/sw/airborne/subsystems/ahrs/ahrs_float_mlkf.c b/sw/airborne/subsystems/ahrs/ahrs_float_mlkf.c index 2b5e0e8d05..8e12989e71 100644 --- a/sw/airborne/subsystems/ahrs/ahrs_float_mlkf.c +++ b/sw/airborne/subsystems/ahrs/ahrs_float_mlkf.c @@ -235,7 +235,7 @@ static inline void update_state(const struct FloatVect3 *i_expected, struct Floa /* converted expected measurement from inertial to body frame */ struct FloatVect3 b_expected; - float_quat_vmult(&b_expected, &ahrs_mlkf.ltp_to_imu_quat, (struct FloatVect3 *)i_expected); + float_quat_vmult(&b_expected, &ahrs_mlkf.ltp_to_imu_quat, i_expected); // S = HPH' + JRJ float H[3][6] = {{ 0., -b_expected.z, b_expected.y, 0., 0., 0.}, @@ -304,7 +304,7 @@ static inline void update_state_heading(const struct FloatVect3 *i_expected, /* converted expected measurement from inertial to body frame */ struct FloatVect3 b_expected; - float_quat_vmult(&b_expected, &ahrs_mlkf.ltp_to_imu_quat, (struct FloatVect3 *)i_expected); + float_quat_vmult(&b_expected, &ahrs_mlkf.ltp_to_imu_quat, i_expected); /* set roll/pitch errors to zero to only correct heading */ struct FloatVect3 i_h_2d = {i_expected->y, -i_expected->x, 0.f};