Compare commits

...

77 Commits

Author SHA1 Message Date
Peter van der Perk 7bbc73b390 Update NuttX (Testing Needs merge it first) 2024-05-04 21:47:55 +02:00
Peter van der Perk beccd10f66 rc_input: Add SINGLEWIRE_MANUAL_DUPLEX for manually changing TXDIR
Fixes telemetry on fmu-v6xrt
2024-05-04 21:47:35 +02:00
Beat Küng 9e6dcb1f60 fix mavlink: cmd_logging_{start,stop}_acknowledgement flags were not reset
Regression from https://github.com/PX4/PX4-Autopilot/pull/23043

Also avoids a race condition by making sure the command ack is handled
before sending out the mavlink message (in case an external component
reacts immediately to the mavlink message).
2024-05-03 06:59:55 +02:00
Alex Klimaj 36ea872e72 drivers: adis16507 reschedule reset after failed self test 2024-05-02 17:52:26 -04:00
Daniel Agar 224d6f2fa7 ekf2: ekf_helper.cpp remove duplicate method comments (comment on declaration only, not definition) 2024-05-02 17:40:58 -04:00
Daniel Agar c1fc893cca ekf2: move gyro/accel/wind covariance reset helpers to covariance.cpp 2024-05-02 17:40:58 -04:00
Daniel Agar 63c2ea33c1 ekf2: move Ekf::resetQuatStateYaw() to yaw_fusion.cpp 2024-05-02 17:40:58 -04:00
Daniel Agar 1ca4056b6a ekf2: delete unused Ekf::resetImuBias() 2024-05-02 17:40:58 -04:00
Daniel Agar 6b3b66619b ekf2: move baro dynamic pressure compensation to aid_sources/barometer 2024-05-02 17:40:58 -04:00
Daniel Agar 4f0eb72fc9 ekf2: move IMU down sampler to imu_down_sampler/ 2024-05-02 17:40:58 -04:00
Daniel Agar 58637d3825 ekf2: move terrain estimator and derivation to terrain_estimator/ 2024-05-02 17:40:58 -04:00
Daniel Agar 58de8cbb77 ekf2: move fake_height, fake_pos, zero_innovation_heading to aid_sources/ 2024-05-02 17:40:58 -04:00
Daniel Agar 49c782bad9 ekf2: move bias estimators to bias_estimtor/ 2024-05-02 17:40:58 -04:00
Daniel Agar e262fde4dc ekf2: move aux global position fusion to aid_sources/aux_global_position 2024-05-02 17:40:58 -04:00
Daniel Agar b8d46e60a5 ekf2: move mag fusion to aid_sources/magnetometer 2024-05-02 17:40:58 -04:00
Daniel Agar 3f6c3e0649 ekf2: move output predictor to output_predictor/ 2024-05-02 17:40:58 -04:00
Daniel Agar 24fdd696cb ekf2: move range finder files to aid_sources/range_finder 2024-05-02 17:40:58 -04:00
Daniel Agar 3dbd3f8a1a ekf2: move airspeed fusion file to aid_sources/airspeed 2024-05-02 17:40:58 -04:00
Daniel Agar 789b2b3d8a ekf2: move sideslip fusion file to aid_sources/sideslip 2024-05-02 17:40:58 -04:00
Daniel Agar eb8ee74066 ekf2: move baro height file to aid_sources/barometer 2024-05-02 17:40:58 -04:00
Daniel Agar de178b1435 ekf2: move gravity fusion file to aid_sources/gravity 2024-05-02 17:40:58 -04:00
Daniel Agar 78f2ccbb60 ekf2: move optical flow files to aid_sources/optical_flow 2024-05-02 17:40:58 -04:00
Daniel Agar fcf94e7670 ekf2: move GNSS files to aid_sources/gnss 2024-05-02 17:40:58 -04:00
Daniel Agar 31ae5b77fe ekf2: move drag_fusion file to aid_sources/drag 2024-05-02 17:40:58 -04:00
Daniel Agar c3fb0b1090 ekf2: move auxvel file to aid_sources/auxvel 2024-05-02 17:40:58 -04:00
Daniel Agar b5d1e87368 ekf2: move EV files to aid_sources/external_vision 2024-05-02 17:40:58 -04:00
Peter van der Perk f382e585e8 sd_bench: Add U option for forcing byte aligned
Co-authored-by: David Sidrane <david.sidrane@nscdg.com>
2024-05-02 12:33:25 -04:00
Daniel Agar c64104e9f1 sensors/vehicle_angular_velocity: silence gyro selection fallback warning (PX4_WARN -> PX4_DEBUG)
- this warning was to catch any potential errors in sensor selection
   relative to what's actually available, we don't need to complain
   about initial selection before the EKF selector is available
2024-05-02 11:53:31 -04:00
David Sidrane c13e3bae12 px4_fmu-v6xrt:Support_MMCSD_MULTIBLOCK with preflight 2024-05-01 20:45:42 -04:00
David Sidrane a3e1dcce4b NuttX with imxrt_sd-preflight backport 2024-05-01 20:45:42 -04:00
Daniel Agar 33234f4dc0 drivers/ins/vectornav: add missing sensor_gps velocity magnitude 2024-05-01 20:40:28 -04:00
Julian Oes e79993a316 gps: split enum after rebase
Signed-off-by: Julian Oes <julian@oes.ch>
2024-05-01 14:42:58 -04:00
alexklimaj b308c4fbcc boards: ark rtk gps safety led open drain 2024-05-01 14:42:58 -04:00
alexklimaj c90ccabbe0 gps: add ZED-F9P-15B 2024-05-01 14:42:58 -04:00
alexklimaj 2498ce6a5c boards: add iis2mdc mag to ark pi6x 2024-04-30 21:26:42 -04:00
alexklimaj 67b39314bf boards: update ark_pi6x EKF delays 2024-04-30 21:26:42 -04:00
Daniel Agar b6da0b141d ekf2: GPS yaw only invalidate yaw_align if stopping due to fusion failure 2024-04-29 21:04:21 -04:00
Beat Küng 547209e1dc libevents: update submodule
And remove obsolete libevents_definitions.h
2024-04-29 07:22:40 -07:00
bresch 9dc7719d4a ekf2: Only reset to GNSS heading if necessary
When North-East (e.g.: GNSS pos/vel) aiding is active, the heading
estimate is constrained and consistent with the vel/pos aiding. Reset to
GNSS heading should only occur if no N-E aiding is active or if the
filter is not yes aligned. Otherwise, just wait for the consistency
check to pass again (will pass at some point if the heading uncertainty
of the filter is getting too high).
2024-04-29 07:22:01 -07:00
Jukka Laitinen 6435e25929 commander: Use PX4_STACK_ADJUSTED to increase stack for 64-bit targets
Signed-off-by: Jukka Laitinen <jukkax@ssrc.tii.ae>
2024-04-29 08:11:54 +02:00
Hamish Willee 902712b97f LogMessage.msg - expand out descriptive string (#23054) 2024-04-29 14:02:09 +12:00
Peter van der Perk 500332e424 imxrt: flexpwm remove 1:1 mapping requirement 2024-04-27 07:57:32 -04:00
Silvan Fuhrer 34cb69898e FW Position Controller: fix Altitude mode without valid z reference (e.g. no GPS)
Signed-off-by: Silvan Fuhrer <silvan@auterion.com>
2024-04-26 10:44:40 +02:00
oravla5 f91103af6e boards: removed CONFIG_SYSTEMCMDS_REFLECT from Sky-Drones AIRLink board support 2024-04-26 09:42:06 +02:00
oravla5 9d6ac0b87a mavlink: Added MAV_{i}_HL_FREQ parameter 2024-04-26 09:42:06 +02:00
oravla5 2b2e1c9521 mavlink: Added parsing of CLI option to configure HL frequency 2024-04-26 09:42:06 +02:00
oravla5 e7b4c5903f px4_cli: Added px4_get_parameter_value function overload for float type 2024-04-26 09:42:06 +02:00
bresch 7cefc3172a estimatorCheck: get param only if handle is valid 2024-04-25 14:48:23 -04:00
murata,katsutoshi ba448fb549 MC Auto: add fixed yaw mode 2024-04-25 13:53:05 +02:00
oravla5 98b23e41f7 mavlink: fixed compilation error after var renaming 2024-04-25 08:23:32 +02:00
oravla5 283ae60a15 telemetry: removed iridium driver 2024-04-25 08:23:32 +02:00
oravla5 3cb48feb61 high_latency_stream: minor PR fix 2024-04-25 08:23:32 +02:00
oravla5 bf1266af11 mavlink: added back gimbal v1 protocol command 2024-04-25 08:23:32 +02:00
oravla5 03652beef8 commander: fixed format 2024-04-25 08:23:32 +02:00
oravla5 d0e7f2c368 high_latency_stream: heading taken from vehicle_attitude topic 2024-04-25 08:23:32 +02:00
Igor Mišić d0532f45b2 telemetry: enable iridium 2024-04-25 08:23:32 +02:00
Igor Mišić 61ca65d863 mavlink: use high_latency_data_link_lost as backup to normal data_link 2024-04-25 08:23:32 +02:00
Igor Mišić 4f8de500af iridiumsbd: update logic for detecting if the modem is not responsive 2024-04-25 08:23:32 +02:00
Igor Mišić 5be0adc779 mavlink: don't send command ACK for internal commands over Iridium 2024-04-25 08:23:32 +02:00
Igor Mišić 29af189cd0 mavlink: don't send events over Iridium 2024-04-25 08:23:32 +02:00
Igor Mišić 208909d471 mavlink: use high_latency_data_link_lost as backup to normal data_link 2024-04-25 08:23:32 +02:00
Igor Mišić de23c10b68 commander: improve handling high latency link lost/regain 2024-04-25 08:23:32 +02:00
Igor Mišić d3b853a7f9 mavlink: fix handling of transmission enable/disable
Co-authored-by: RomanBapst <bapstroman@gmail.com>
2024-04-25 08:23:32 +02:00
Igor Mišić 760bcdec2f high_latency_stream: fixed bug where fields were not updating
- topic update was checked twice in the same loop and thus
the second time the topic would never indicate to have updated

Co-authored-by: RomanBapst <bapstroman@gmail.com>
2024-04-25 08:23:32 +02:00
Igor Mišić df2cc4af05 commander: fix check for availability of high latency link
Signed-off-by: RomanBapst <bapstroman@gmail.com>
2024-04-25 08:23:32 +02:00
Beat Küng f543951e10 commander: set correct health component when reporting errors 2024-04-24 16:06:32 -04:00
Jacob Dahl 69e082c83d drivers/magnetometer: new ST IIS2MDC Magnetometer driver 2024-04-24 13:01:18 -07:00
dirksavage88 6a3e57d428 Shift vertical orientation above scaling yaw operation, cp angle sign change
Signed-off-by: dirksavage88 <dirksavage88@gmail.com>
2024-04-24 15:58:12 -04:00
dirksavage88 0f6f4c5b07 fix to orientation offsets for scaled yaw, removed unused param
Signed-off-by: dirksavage88 <dirksavage88@gmail.com>
2024-04-24 15:58:12 -04:00
Thomas Frans 65c7e034dc VSCode: add EditorConfig extension to recommended and devcontainer.json 2024-04-24 15:52:23 -04:00
Daniel Agar eb59bb9de9 simulation/gz_bridge: eliminate implicit float conversion 2024-04-24 15:51:30 -04:00
bresch b508df39a2 imu consistency: don't scale param threshold 2024-04-24 15:51:07 -04:00
bresch 8bf1cf0b15 ekf2_params: reduce "short" description 2024-04-24 15:09:57 -04:00
Silvan Fuhrer 97191bd60f autopilot_tester: for mission end timeout check take speed factor into account
And increase the (simulation time) timeouts.

Signed-off-by: Silvan Fuhrer <silvan@auterion.com>
2024-04-23 16:37:31 +02:00
Silvan Fuhrer 818e318334 autopilot_tester: reduce mission distance for wind world
Signed-off-by: Silvan Fuhrer <silvan@auterion.com>
2024-04-23 16:37:31 +02:00
Silvan Fuhrer 59232c27ae autopilot_tester: use normal VTOL mission for airspeed blockage test
Signed-off-by: Silvan Fuhrer <silvan@auterion.com>
2024-04-23 16:37:31 +02:00
fury1895 2683128205 PM Selector Auterion: remove INA226_SHUNT value reset (skynode only) 2024-04-23 16:02:35 +02:00
126 changed files with 1620 additions and 815 deletions
+1
View File
@@ -15,6 +15,7 @@
"extensions": [
"chiehyu.vscode-astyle",
"dan-c-underwood.arm",
"editorconfig.editorconfig",
"fredericbonnet.cmake-test-adapter",
"github.vscode-pull-request-github",
"marus25.cortex-debug",
+1
View File
@@ -4,6 +4,7 @@
"recommendations": [
"chiehyu.vscode-astyle",
"dan-c-underwood.arm",
"editorconfig.editorconfig",
"fredericbonnet.cmake-test-adapter",
"github.vscode-pull-request-github",
"marus25.cortex-debug",
@@ -34,24 +34,23 @@ def extract_timer(line):
if search:
return search.group(1), 'generic'
# nxp rt1062 format: initIOPWM(PWM::FlexPWM2),
search = re.search('PWM::Flex([0-9a-zA-Z_]+)[,\)]', line, re.IGNORECASE)
# NXP FlexPWM format format: initIOPWM(PWM::FlexPWM2),
search = re.search('PWM::Flex([0-9a-zA-Z_]+)..PWM::Submodule([0-9])[,\)]', line, re.IGNORECASE)
if search:
return search.group(1), 'imxrt'
return (search.group(1) + '_' + search.group(2)), 'imxrt'
return None, 'unknown'
def extract_timer_from_channel(line, num_channels_already_found):
def extract_timer_from_channel(line, timer_names):
# Try format: initIOTimerChannel(io_timers, {Timer::Timer5, Timer::Channel1}, {GPIO::PortA, GPIO::Pin0}),
search = re.search('Timer::([0-9a-zA-Z_]+), ', line, re.IGNORECASE)
if search:
return search.group(1)
# nxp rt1062 format: initIOTimerChannel(io_timers, {PWM::PWM2_PWM_A, PWM::Submodule0}, IOMUX::Pad::GPIO_B0_06),
search = re.search('PWM::(PWM[0-9]+)[_,\)]', line, re.IGNORECASE)
# NXP FlexPWM format: initIOTimerChannel(io_timers, {PWM::PWM2_PWM_A, PWM::Submodule0}, IOMUX::Pad::GPIO_B0_06),
search = re.search('PWM::(PWM[0-9]+).*PWM::Submodule([0-9])', line, re.IGNORECASE)
if search:
# imxrt uses a 1:1 timer group to channel association
return str(num_channels_already_found)
return str(timer_names.index((search.group(1) + '_' + search.group(2))))
return None
@@ -69,6 +68,7 @@ def get_timer_groups(timer_config_file, verbose=False):
open_idx, close_idx = find_matching_brackets(('{', '}'), timer_config, verbose)
timers_str = timer_config[open_idx:close_idx]
timers = []
timer_names = []
for line in timers_str.splitlines():
line = line.strip()
if len(line) == 0 or line.startswith('//'):
@@ -77,14 +77,12 @@ def get_timer_groups(timer_config_file, verbose=False):
if timer_type == 'imxrt':
if verbose: print('imxrt timer found')
max_num_channels = 16 # Just add a fixed number of timers
timers = [str(i) for i in range(max_num_channels)]
dshot_support = {str(i): False for i in range(max_num_channels)}
timer_names.append(timer)
timers.append(str(len(timers)))
dshot_support = {str(i): False for i in range(16)}
for i in range(8): # First 8 channels support dshot
dshot_support[str(i)] = True
break
if timer:
elif timer:
if verbose: print('found timer def: {:}'.format(timer))
dshot_support[timer] = 'DMA' in line
timers.append(timer)
@@ -111,7 +109,7 @@ def get_timer_groups(timer_config_file, verbose=False):
continue
if verbose: print('--'+line+'--')
timer = extract_timer_from_channel(line, len(channel_timers))
timer = extract_timer_from_channel(line, timer_names)
if timer:
if verbose: print('Found timer: {:} in channel line {:}'.format(timer, line))
@@ -6,6 +6,7 @@
param set-default CBRK_IO_SAFETY 0
param set-default CANNODE_SUB_MBD 1
param set-default CANNODE_SUB_RTCM 1
param set-default GPS_1_GNSS 63
param set-default MBE_ENABLE 1
param set-default SENS_IMU_CLPNOTI 0
+1 -1
View File
@@ -47,7 +47,7 @@
#define GPIO_BTN_SAFETY /* PB15 */ (GPIO_INPUT|GPIO_PULLDOWN|GPIO_PORTB|GPIO_PIN15)
/* Safety LED */
#define GPIO_LED_SAFETY /* PA1 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_SET|GPIO_PORTA|GPIO_PIN1)
#define GPIO_LED_SAFETY /* PA1 */ (GPIO_OUTPUT|GPIO_OPENDRAIN|GPIO_SPEED_2MHz|GPIO_OUTPUT_SET|GPIO_PORTA|GPIO_PIN1)
/* Tone alarm output. */
#define TONE_ALARM_TIMER 2 /* timer 2 */
+1
View File
@@ -15,6 +15,7 @@ CONFIG_DRIVERS_HEATER=y
CONFIG_DRIVERS_IMU_INVENSENSE_ICM42688P=y
CONFIG_COMMON_LIGHT=y
CONFIG_DRIVERS_MAGNETOMETER_MEMSIC_MMC5983MA=y
CONFIG_DRIVERS_MAGNETOMETER_ST_IIS2MDC=y
CONFIG_DRIVERS_OPTICAL_FLOW_PAW3902=y
CONFIG_DRIVERS_POWER_MONITOR_INA226=y
CONFIG_DRIVERS_PWM_OUT=y
+5 -5
View File
@@ -32,17 +32,17 @@ then
param set-default SENS_TEMP_ID 2490378
fi
param set-default EKF2_BARO_DELAY 13
param set-default EKF2_BARO_DELAY 39
param set-default EKF2_BARO_NOISE 0.9
param set-default EKF2_HGT_REF 2
param set-default EKF2_MAG_DELAY 100
param set-default EKF2_HGT_REF 0
param set-default EKF2_MAG_DELAY 60
param set-default EKF2_MAG_NOISE 0.06
param set-default EKF2_MULTI_IMU 2
param set-default EKF2_OF_CTRL 1
param set-default EKF2_OF_DELAY 48
param set-default EKF2_OF_DELAY 28
param set-default EKF2_OF_N_MIN 0.05
param set-default EKF2_RNG_A_HMAX 25
param set-default EKF2_RNG_DELAY 48
param set-default EKF2_RNG_DELAY 105
param set-default EKF2_RNG_NOISE 0.03
param set-default EKF2_RNG_QLTY_T 0.1
param set-default EKF2_RNG_SFE 0.03
+4 -2
View File
@@ -21,8 +21,10 @@ then
fi
# Internal magnetometer on I2C
# TODO: Write a driver for the MMC5983MA
mmc5983ma -I -b 4 start
if ! iis2mdc -R 4 -I -b 4 start
then
mmc5983ma -I -b 4 start
fi
# Internal Baro on I2C
bmp388 -I -b 4 start
@@ -185,7 +185,6 @@ CONFIG_LPUART8_TXDMA=y
CONFIG_MEMSET_64BIT=y
CONFIG_MEMSET_OPTSPEED=y
CONFIG_MMCSD=y
CONFIG_MMCSD_MULTIBLOCK_LIMIT=1
CONFIG_MMCSD_SDIO=y
CONFIG_MTD=y
CONFIG_MTD_BYTE_WRITE=y
+6 -4
View File
@@ -451,10 +451,12 @@
#define HRT_PPM_CHANNEL /* GPIO_EMC_B1_09 GPIO_GPT5_CAPTURE1_1 */ 1 /* use capture/compare channel 1 */
#define GPIO_PPM_IN /* GPIO_EMC_B1_09 GPT1_CAPTURE2 */ (GPIO_GPT5_CAPTURE1_1 | GENERAL_INPUT_IOMUX)
#define RC_SERIAL_PORT "/dev/ttyS4"
#define RC_SERIAL_SINGLEWIRE 1 // Suport Single wire wiring
#define RC_SERIAL_SWAP_RXTX 1 // Set Swap (but not supported in HW) to use Single wire
#define RC_SERIAL_SWAP_USING_SINGLEWIRE 1 // Set to use Single wire swap as HW does not support swap
#define RC_SERIAL_PORT "/dev/ttyS4"
#define RC_SERIAL_SINGLEWIRE 1 // Suport Single wire wiring
#define RC_SERIAL_SWAP_RXTX 1 // Set Swap (but not supported in HW) to use Single wire
#define RC_SERIAL_SWAP_USING_SINGLEWIRE 1 // Set to use Single wire swap as HW does not support swap
#define RC_SERIAL_SINGLEWIRE_MANUAL_DUPLEX 1 // Set to use ioctl's to manually swap duplex
#define BOARD_SUPPORTS_RC_SERIAL_PORT_OUTPUT
/* FLEXSPI4 */
@@ -86,7 +86,6 @@ CONFIG_SYSTEMCMDS_NSHTERM=y
CONFIG_SYSTEMCMDS_PARAM=y
CONFIG_SYSTEMCMDS_PERF=y
CONFIG_SYSTEMCMDS_REBOOT=y
CONFIG_SYSTEMCMDS_REFLECT=y
CONFIG_SYSTEMCMDS_SD_BENCH=y
CONFIG_SYSTEMCMDS_SD_STRESS=y
CONFIG_SYSTEMCMDS_SERIAL_TEST=y
+1 -1
View File
@@ -1,5 +1,5 @@
uint64 timestamp # time since system start (microseconds)
uint64 last_heartbeat # timestamp of the last successful sbd session
uint64 last_at_ok_timestamp # timestamp of the last "OK" received after the "AT" command
uint16 tx_buf_write_index # current size of the tx buffer
uint16 rx_buf_read_index # the rx buffer is parsed up to that index
uint16 rx_buf_end_index # current size of the rx buffer
+1 -1
View File
@@ -1,4 +1,4 @@
# A logging message, output with PX4_{WARN,ERR,INFO}
# A logging message, output with PX4_WARN, PX4_ERR, PX4_INFO
uint64 timestamp # time since system start (microseconds)
@@ -50,3 +50,15 @@
* @return 0 on success, -errno otherwise
*/
int px4_get_parameter_value(const char *option, int &value);
/**
* Parse a CLI argument to a float. There are 2 valid formats:
* - 'p:<param_name>'
* in this case the parameter is loaded from an integer parameter
* - <float>
* a floating-point value, so just a string to float conversion is done
* @param option CLI argument
* @param value returned value
* @return 0 on success, -errno otherwise
*/
int px4_get_parameter_value(const char *option, float &value);
@@ -45,7 +45,7 @@
#endif
#include <events/events_generated.h>
#include <libevents_definitions.h>
#include <uORB/topics/event.h>
#include <stdint.h>
@@ -93,7 +93,7 @@ constexpr unsigned sizeofArguments(const T &t, const Args &... args)
/**
* publish/send an event
*/
void send(EventType &event);
void send(event_s &event);
/**
* Generate event ID from an event name
@@ -109,7 +109,7 @@ constexpr uint32_t ID(const char (&name)[N])
template<typename... Args>
inline void send(uint32_t id, const LogLevels &log_levels, const char *message, Args... args)
{
EventType e{};
event_s e{};
e.log_levels = ((uint8_t)log_levels.internal << 4) | (uint8_t)log_levels.external;
e.id = id;
static_assert(util::sizeofArguments(args...) <= sizeof(e.arguments), "Too many arguments");
@@ -120,7 +120,7 @@ inline void send(uint32_t id, const LogLevels &log_levels, const char *message,
inline void send(uint32_t id, const LogLevels &log_levels, const char *message)
{
EventType e{};
event_s e{};
e.log_levels = ((uint8_t)log_levels.internal << 4) | (uint8_t)log_levels.external;
e.id = id;
CONSOLE_PRINT_EVENT(e.log_level_external, e.id, message);
+46
View File
@@ -59,6 +59,7 @@ int px4_get_parameter_value(const char *option, int &value)
if (param_handle != PARAM_INVALID) {
if (param_type(param_handle) != PARAM_TYPE_INT32) {
PX4_ERR("Type of param '%s' is different from INT32", param_name);
return -EINVAL;
}
@@ -87,3 +88,48 @@ int px4_get_parameter_value(const char *option, int &value)
return 0;
}
int px4_get_parameter_value(const char *option, float &value)
{
value = 0;
/* check if this is a param name */
if (strncmp("p:", option, 2) == 0) {
const char *param_name = option + 2;
/* user wants to use a param name */
param_t param_handle = param_find(param_name);
if (param_handle != PARAM_INVALID) {
if (param_type(param_handle) != PARAM_TYPE_FLOAT) {
PX4_ERR("Type of param '%s' is different from FLOAT", param_name);
return -EINVAL;
}
float pwm_parm;
int ret = param_get(param_handle, &pwm_parm);
if (ret != 0) {
return ret;
}
value = pwm_parm;
} else {
PX4_ERR("param name '%s' not found", param_name);
return -ENXIO;
}
} else {
char *ep;
value = strtof(option, &ep);
if (*ep != '\0') {
return -EINVAL;
}
}
return 0;
}
@@ -255,6 +255,34 @@ static inline int channels_timer(unsigned channel)
return timer_io_channels[channel].timer_index;
}
static uint32_t get_timer_channels(unsigned timer)
{
uint32_t channels = 0;
static uint32_t channels_cache[MAX_IO_TIMERS] = {0};
if (validate_timer_index(timer) < 0) {
return channels;
} else {
if (channels_cache[timer] == 0) {
/* Gather the channel bits that belong to the timer */
uint32_t first_channel_index = io_timers_channel_mapping.element[timer].first_channel_index;
uint32_t last_channel_index = first_channel_index + io_timers_channel_mapping.element[timer].channel_count;
for (unsigned chan_index = first_channel_index; chan_index < last_channel_index; chan_index++) {
channels |= 1 << chan_index;
}
/* cache them */
channels_cache[timer] = channels;
}
}
return channels_cache[timer];
}
static uint32_t get_channel_mask(unsigned channel)
{
return io_timer_validate_channel_index(channel) == 0 ? 1 << channel : 0;
@@ -391,41 +419,66 @@ static int allocate_channel(unsigned channel, io_timer_channel_mode_t mode)
return rv;
}
static int timer_set_rate(unsigned channel, unsigned rate)
static int timer_set_rate(unsigned timer, unsigned rate)
{
int channels = get_timer_channels(timer);
irqstate_t flags = px4_enter_critical_section();
rMCTRL(channels_timer(channel)) |= (timer_io_channels[channel].sub_module_bits >> MCTRL_LDOK_SHIFT) << MCTRL_CLDOK_SHIFT
;
rVAL1(channels_timer(channel), timer_io_channels[channel].sub_module) = (BOARD_PWM_FREQ / rate) - 1;
rMCTRL(channels_timer(channel)) |= timer_io_channels[channel].sub_module_bits;
for (uint32_t channel = 0; channel < DIRECT_PWM_OUTPUT_CHANNELS; ++channel) {
if ((1 << channel) & channels) {
rMCTRL(channels_timer(channel)) |= (timer_io_channels[channel].sub_module_bits >> MCTRL_LDOK_SHIFT) << MCTRL_CLDOK_SHIFT
;
rVAL1(channels_timer(channel), timer_io_channels[channel].sub_module) = (BOARD_PWM_FREQ / rate) - 1;
rMCTRL(channels_timer(channel)) |= timer_io_channels[channel].sub_module_bits;
}
}
px4_leave_critical_section(flags);
return 0;
}
static inline void io_timer_set_oneshot_mode(unsigned channel)
static inline void io_timer_set_oneshot_mode(unsigned timer)
{
int channels = get_timer_channels(timer);
irqstate_t flags = px4_enter_critical_section();
uint16_t rvalue = rCTRL(channels_timer(channel), timer_io_channels[channel].sub_module);
rvalue &= ~SMCTRL_PRSC_MASK;
rvalue |= SMCTRL_PRSC_DIV2 | SMCTRL_LDMOD;
rMCTRL(channels_timer(channel)) |= (timer_io_channels[channel].sub_module_bits >> MCTRL_LDOK_SHIFT) << MCTRL_CLDOK_SHIFT
;
rCTRL(channels_timer(channel), timer_io_channels[channel].sub_module) = rvalue;
rMCTRL(channels_timer(channel)) |= timer_io_channels[channel].sub_module_bits;
for (uint32_t channel = 0; channel < DIRECT_PWM_OUTPUT_CHANNELS; ++channel) {
if ((1 << channel) & channels) {
uint16_t rvalue = rCTRL(channels_timer(channel), timer_io_channels[channel].sub_module);
rvalue &= ~SMCTRL_PRSC_MASK;
rvalue |= SMCTRL_PRSC_DIV2 | SMCTRL_LDMOD;
rMCTRL(channels_timer(channel)) |= (timer_io_channels[channel].sub_module_bits >> MCTRL_LDOK_SHIFT) << MCTRL_CLDOK_SHIFT
;
rCTRL(channels_timer(channel), timer_io_channels[channel].sub_module) = rvalue;
rMCTRL(channels_timer(channel)) |= timer_io_channels[channel].sub_module_bits;
}
}
px4_leave_critical_section(flags);
}
static inline void io_timer_set_PWM_mode(unsigned channel)
static inline void io_timer_set_PWM_mode(unsigned timer)
{
int channels = get_timer_channels(timer);
irqstate_t flags = px4_enter_critical_section();
uint16_t rvalue = rCTRL(channels_timer(channel), timer_io_channels[channel].sub_module);
rvalue &= ~(SMCTRL_PRSC_MASK | SMCTRL_LDMOD);
rvalue |= SMCTRL_PRSC_DIV16;
rMCTRL(channels_timer(channel)) |= (timer_io_channels[channel].sub_module_bits >> MCTRL_LDOK_SHIFT) << MCTRL_CLDOK_SHIFT
;
rCTRL(channels_timer(channel), timer_io_channels[channel].sub_module) = rvalue;
rMCTRL(channels_timer(channel)) |= timer_io_channels[channel].sub_module_bits;
for (uint32_t channel = 0; channel < DIRECT_PWM_OUTPUT_CHANNELS; ++channel) {
if ((1 << channel) & channels) {
uint16_t rvalue = rCTRL(channels_timer(channel), timer_io_channels[channel].sub_module);
rvalue &= ~(SMCTRL_PRSC_MASK | SMCTRL_LDMOD);
rvalue |= SMCTRL_PRSC_DIV16;
rMCTRL(channels_timer(channel)) |= (timer_io_channels[channel].sub_module_bits >> MCTRL_LDOK_SHIFT) << MCTRL_CLDOK_SHIFT
;
rCTRL(channels_timer(channel), timer_io_channels[channel].sub_module) = rvalue;
rMCTRL(channels_timer(channel)) |= timer_io_channels[channel].sub_module_bits;
}
}
px4_leave_critical_section(flags);
}
@@ -530,33 +583,35 @@ int io_timer_init_timer(unsigned timer, io_timer_channel_mode_t mode)
break;
}
uint32_t first_channel_index = io_timers_channel_mapping.element[timer].first_channel_index;
uint32_t last_channel_index = first_channel_index + io_timers_channel_mapping.element[timer].channel_count;
int channels = get_timer_channels(timer);
for (uint32_t chan = first_channel_index; chan < last_channel_index; chan++) {
for (uint32_t chan = 0; chan < DIRECT_PWM_OUTPUT_CHANNELS; ++chan) {
if ((1 << chan) & channels) {
/* Clear all Faults */
rFSTS0(timer) = FSTS_FFLAG_MASK;
/* Clear all Faults */
rFSTS0(timer) = FSTS_FFLAG_MASK;
rCTRL2(timer, timer_io_channels[chan].sub_module) = SMCTRL2_CLK_SEL_EXT_CLK | SMCTRL2_DBGEN | SMCTRL2_INDEP;
rCTRL(timer, timer_io_channels[chan].sub_module) = SMCTRL_PRSC_DIV16 | SMCTRL_FULL;
/* Edge aligned at 0 */
rINIT(channels_timer(chan), timer_io_channels[chan].sub_module) = 0;
rVAL0(channels_timer(chan), timer_io_channels[chan].sub_module) = 0;
rVAL2(channels_timer(chan), timer_io_channels[chan].sub_module) = 0;
rVAL4(channels_timer(chan), timer_io_channels[chan].sub_module) = 0;
rFFILT0(timer) &= ~FFILT_FILT_PER_MASK;
rDISMAP0(timer, timer_io_channels[chan].sub_module) = 0xf000;
rDISMAP1(timer, timer_io_channels[chan].sub_module) = 0xf000;
rOUTEN(timer) |= timer_io_channels[chan].val_offset == PWMA_VAL ? OUTEN_PWMA_EN(1 << timer_io_channels[chan].sub_module)
: OUTEN_PWMB_EN(1 << timer_io_channels[chan].sub_module);
rDTSRCSEL(timer) = 0;
rMCTRL(timer) = MCTRL_LDOK(1 << timer_io_channels[chan].sub_module);
rMCTRL(timer) = timer_io_channels[chan].sub_module_bits;
io_timer_set_PWM_mode(chan);
timer_set_rate(chan, 50);
rCTRL2(timer, timer_io_channels[chan].sub_module) = SMCTRL2_CLK_SEL_EXT_CLK | SMCTRL2_DBGEN | SMCTRL2_INDEP;
rCTRL(timer, timer_io_channels[chan].sub_module) = SMCTRL_PRSC_DIV16 | SMCTRL_FULL;
/* Edge aligned at 0 */
rINIT(channels_timer(chan), timer_io_channels[chan].sub_module) = 0;
rVAL0(channels_timer(chan), timer_io_channels[chan].sub_module) = 0;
rVAL2(channels_timer(chan), timer_io_channels[chan].sub_module) = 0;
rVAL4(channels_timer(chan), timer_io_channels[chan].sub_module) = 0;
rFFILT0(timer) &= ~FFILT_FILT_PER_MASK;
rDISMAP0(timer, timer_io_channels[chan].sub_module) = 0xf000;
rDISMAP1(timer, timer_io_channels[chan].sub_module) = 0xf000;
rOUTEN(timer) |= timer_io_channels[chan].val_offset == PWMA_VAL ? OUTEN_PWMA_EN(1 << timer_io_channels[chan].sub_module)
: OUTEN_PWMB_EN(1 << timer_io_channels[chan].sub_module);
rDTSRCSEL(timer) = 0;
rMCTRL(timer) = MCTRL_LDOK(1 << timer_io_channels[chan].sub_module);
rMCTRL(timer) = timer_io_channels[chan].sub_module_bits;
}
}
io_timer_set_PWM_mode(timer);
timer_set_rate(timer, 50);
px4_leave_critical_section(flags);
}
@@ -818,8 +873,7 @@ uint16_t io_channel_get_ccr(unsigned channel)
return value;
}
// The rt has 1:1 group to channel
uint32_t io_timer_get_group(unsigned group)
uint32_t io_timer_get_group(unsigned timer)
{
return get_channel_mask(group);
return get_timer_channels(timer);
}
@@ -75,7 +75,7 @@ SF45LaserSerial::SF45LaserSerial(const char *port, uint8_t rotation) :
// populate obstacle map members
_obstacle_map_msg.frame = obstacle_distance_s::MAV_FRAME_BODY_FRD;
_obstacle_map_msg.increment = 5;
_obstacle_map_msg.angle_offset = -2.5;
_obstacle_map_msg.angle_offset = 2.5;
_obstacle_map_msg.min_distance = UINT16_MAX;
_obstacle_map_msg.max_distance = 5000;
@@ -157,7 +157,6 @@ int SF45LaserSerial::collect()
int64_t read_elapsed = hrt_elapsed_time(&_last_read);
int ret;
/* the buffer for read chars is buflen minus null termination */
param_get(param_find("SF45_CP_LIMIT"), &_collision_constraint);
uint8_t readbuf[SF45_MAX_PAYLOAD];
float distance_m = -1.0f;
@@ -669,34 +668,35 @@ void SF45LaserSerial::sf45_process_replies(float *distance_m)
raw_yaw = raw_yaw * -1;
}
// SF45/B product guide {Data output bit: 8 Description: "Yaw angle [1/100 deg] size: int16}"
scaled_yaw = raw_yaw * SF45_SCALE_FACTOR;
switch (_yaw_cfg) {
case 0:
break;
case 1:
if (raw_yaw > 180) {
raw_yaw = raw_yaw - 180;
if (scaled_yaw > 180) {
scaled_yaw = scaled_yaw - 180;
} else {
raw_yaw = raw_yaw + 180; // rotation facing aft
scaled_yaw = scaled_yaw + 180; // rotation facing aft
}
break;
case 2:
raw_yaw = raw_yaw + 90; // rotation facing right
scaled_yaw = scaled_yaw + 90; // rotation facing right
break;
case 3:
raw_yaw = raw_yaw - 90; // rotation facing left
scaled_yaw = scaled_yaw - 90; // rotation facing left
break;
default:
break;
}
scaled_yaw = raw_yaw * SF45_SCALE_FACTOR;
// Convert to meters for rangefinder update
*distance_m = raw_distance * SF45_SCALE_FACTOR;
obstacle_dist_cm = (uint16_t)raw_distance;
+1
View File
@@ -64,6 +64,7 @@
#define DRV_MAG_DEVTYPE_IST8308 0x0B
#define DRV_MAG_DEVTYPE_LIS2MDL 0x0C
#define DRV_MAG_DEVTYPE_MMC5983MA 0x0D
#define DRV_MAG_DEVTYPE_IIS2MDC 0x0E
#define DRV_IMU_DEVTYPE_LSM303D 0x11
+2 -1
View File
@@ -939,7 +939,8 @@ GPS::run()
set_device_type(DRV_GPS_DEVTYPE_UBX_9);
break;
case GPSDriverUBX::Board::u_blox9_F9P:
case GPSDriverUBX::Board::u_blox9_F9P_L1L2:
case GPSDriverUBX::Board::u_blox9_F9P_L1L5:
set_device_type(DRV_GPS_DEVTYPE_UBX_F9P);
break;
+6 -2
View File
@@ -247,14 +247,16 @@ PARAM_DEFINE_INT32(GPS_2_PROTOCOL, 1);
* 2 : Use Galileo
* 3 : Use BeiDou
* 4 : Use GLONASS
* 5 : Use NAVIC
*
* @min 0
* @max 31
* @max 63
* @bit 0 GPS (with QZSS)
* @bit 1 SBAS
* @bit 2 Galileo
* @bit 3 BeiDou
* @bit 4 GLONASS
* @bit 5 NAVIC
*
* @reboot_required true
* @group GPS
@@ -277,14 +279,16 @@ PARAM_DEFINE_INT32(GPS_1_GNSS, 0);
* 2 : Use Galileo
* 3 : Use BeiDou
* 4 : Use GLONASS
* 5 : Use NAVIC
*
* @min 0
* @max 31
* @max 63
* @bit 0 GPS (with QZSS)
* @bit 1 SBAS
* @bit 2 Galileo
* @bit 3 BeiDou
* @bit 4 GLONASS
* @bit 5 NAVIC
*
* @reboot_required true
* @group GPS
@@ -172,7 +172,9 @@ void ADIS16507::RunImpl()
const uint16_t DIAG_STAT = RegisterRead(Register::DIAG_STAT);
if (DIAG_STAT != 0) {
PX4_ERR("DIAG_STAT: %#X", DIAG_STAT);
PX4_ERR("self test failed, resetting. DIAG_STAT: %#X", DIAG_STAT);
_state = STATE::RESET;
ScheduleDelayed(3_s);
} else {
PX4_DEBUG("self test passed");
+2 -1
View File
@@ -441,10 +441,11 @@ void VectorNav::sensorCallback(VnUartPacket *packet)
sensor_gps.altitude_msl_m = positionGpsLla.c[2];
sensor_gps.altitude_ellipsoid_m = sensor_gps.altitude_msl_m;
sensor_gps.vel_ned_valid = true;
sensor_gps.vel_m_s = matrix::Vector3f(velocityGpsNed.c).length();
sensor_gps.vel_n_m_s = velocityGpsNed.c[0];
sensor_gps.vel_e_m_s = velocityGpsNed.c[1];
sensor_gps.vel_d_m_s = velocityGpsNed.c[2];
sensor_gps.vel_ned_valid = true;
sensor_gps.hdop = dop.hDOP;
sensor_gps.vdop = dop.vDOP;
+1
View File
@@ -41,4 +41,5 @@ add_subdirectory(lis3mdl)
add_subdirectory(lsm303agr)
add_subdirectory(memsic)
add_subdirectory(rm3100)
add_subdirectory(st)
add_subdirectory(vtrantech)
+1
View File
@@ -14,6 +14,7 @@ menu "Magnetometer"
select DRIVERS_MAGNETOMETER_RM3100
select DRIVERS_MAGNETOMETER_VTRANTECH_VCM1193L
select DRIVERS_MAGNETOMETER_MEMSIC_MMC5983MA
select DRIVERS_MAGNETOMETER_ST_IIS2MDC
---help---
Enable default set of magnetometer drivers
rsource "*/Kconfig"
+3
View File
@@ -0,0 +1,3 @@
menu "ST"
rsource "*/Kconfig"
endmenu
@@ -0,0 +1,45 @@
############################################################################
#
# Copyright (c) 2024 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_module(
MODULE drivers__magnetometer__st__iis2mdc
MAIN iis2mdc
COMPILE_FLAGS
# -DDEBUG_BUILD
SRCS
iis2mdc_i2c.cpp
iis2mdc_main.cpp
iis2mdc.cpp
DEPENDS
drivers_magnetometer
px4_work_queue
)
@@ -0,0 +1,5 @@
menuconfig DRIVERS_MAGNETOMETER_ST_IIS2MDC
bool "iis2mdc"
default n
---help---
Enable support for iis2mdc
@@ -0,0 +1,137 @@
/****************************************************************************
*
* Copyright (c) 2024 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#include "iis2mdc.h"
using namespace time_literals;
IIS2MDC::IIS2MDC(device::Device *interface, const I2CSPIDriverConfig &config) :
I2CSPIDriver(config),
_interface(interface),
_px4_mag(interface->get_device_id(), config.rotation),
_sample_count(perf_alloc(PC_COUNT, "iis2mdc_read")),
_comms_errors(perf_alloc(PC_COUNT, "iis2mdc_comms_errors"))
{}
IIS2MDC::~IIS2MDC()
{
perf_free(_sample_count);
perf_free(_comms_errors);
delete _interface;
}
int IIS2MDC::init()
{
if (hrt_absolute_time() < 20_ms) {
px4_usleep(20_ms); // ~10ms power-on time
}
write_register(IIS2MDC_ADDR_CFG_REG_A, MD_CONTINUOUS | ODR_100 | COMP_TEMP_EN);
write_register(IIS2MDC_ADDR_CFG_REG_B, OFF_CANC);
write_register(IIS2MDC_ADDR_CFG_REG_C, BDU);
_px4_mag.set_scale(100.f / 65535.f); // +/- 50 Gauss, 16bit
ScheduleDelayed(20_ms);
return PX4_OK;
}
void IIS2MDC::RunImpl()
{
uint8_t status = read_register(IIS2MDC_ADDR_STATUS_REG);
if (status & IIS2MDC_STATUS_REG_READY) {
SensorData data = {};
if (read_register_block(&data) == PX4_OK) {
int16_t x = int16_t((data.xout1 << 8) | data.xout0);
int16_t y = int16_t((data.yout1 << 8) | data.yout0);
int16_t z = -int16_t((data.zout1 << 8) | data.zout0);
int16_t t = int16_t((data.tout1 << 8) | data.tout0);
// 16 bits twos complement with a sensitivity of 8 LSB/°C. Typically, the output zero level corresponds to 25 °C.
_px4_mag.set_temperature(float(t) / 8.f + 25.f);
_px4_mag.update(hrt_absolute_time(), x, y, z);
_px4_mag.set_error_count(perf_event_count(_comms_errors));
perf_count(_sample_count);
} else {
PX4_DEBUG("read failed");
perf_count(_comms_errors);
}
} else {
PX4_DEBUG("not ready: %u", status);
perf_count(_comms_errors);
}
ScheduleDelayed(10_ms);
}
uint8_t IIS2MDC::read_register_block(SensorData *data)
{
uint8_t reg = IIS2MDC_ADDR_OUTX_L_REG;
if (_interface->read(reg, data, sizeof(SensorData)) != PX4_OK) {
perf_count(_comms_errors);
return PX4_ERROR;
}
return PX4_OK;
}
uint8_t IIS2MDC::read_register(uint8_t reg)
{
uint8_t value = 0;
if (_interface->read(reg, &value, sizeof(value)) != PX4_OK) {
perf_count(_comms_errors);
}
return value;
}
void IIS2MDC::write_register(uint8_t reg, uint8_t value)
{
if (_interface->write(reg, &value, sizeof(value)) != PX4_OK) {
perf_count(_comms_errors);
}
}
void IIS2MDC::print_status()
{
I2CSPIDriverBase::print_status();
perf_print_counter(_sample_count);
perf_print_counter(_comms_errors);
}
@@ -0,0 +1,95 @@
/****************************************************************************
*
* Copyright (c) 2024 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#pragma once
#include <px4_platform_common/i2c_spi_buses.h>
#include <lib/drivers/magnetometer/PX4Magnetometer.hpp>
// IIS2MDC Registers
#define IIS2MDC_ADDR_CFG_REG_A 0x60
#define IIS2MDC_ADDR_CFG_REG_B 0x61
#define IIS2MDC_ADDR_CFG_REG_C 0x62
#define IIS2MDC_ADDR_STATUS_REG 0x67
#define IIS2MDC_ADDR_OUTX_L_REG 0x68
#define IIS2MDC_ADDR_WHO_AM_I 0x4F
// IIS2MDC Definitions
#define IIS2MDC_WHO_AM_I 0b01000000
#define IIS2MDC_STATUS_REG_READY 0b00001111
// CFG_REG_A
#define COMP_TEMP_EN (1 << 7)
#define MD_CONTINUOUS (0 << 0)
#define ODR_100 ((1 << 3) | (1 << 2))
// CFG_REG_B
#define OFF_CANC (1 << 1)
// CFG_REG_C
#define BDU (1 << 4)
extern device::Device *IIS2MDC_I2C_interface(const I2CSPIDriverConfig &config);
class IIS2MDC : public I2CSPIDriver<IIS2MDC>
{
public:
IIS2MDC(device::Device *interface, const I2CSPIDriverConfig &config);
virtual ~IIS2MDC();
struct SensorData {
uint8_t xout0;
uint8_t xout1;
uint8_t yout0;
uint8_t yout1;
uint8_t zout0;
uint8_t zout1;
uint8_t tout0;
uint8_t tout1;
};
static I2CSPIDriverBase *instantiate(const I2CSPIDriverConfig &config, int runtime_instance);
static void print_usage();
int init();
void print_status() override;
void RunImpl();
private:
uint8_t read_register_block(SensorData *data);
uint8_t read_register(uint8_t reg);
void write_register(uint8_t reg, uint8_t value);
device::Device *_interface;
PX4Magnetometer _px4_mag;
perf_counter_t _sample_count;
perf_counter_t _comms_errors;
};
@@ -1,6 +1,6 @@
/****************************************************************************
*
* Copyright (c) 2020 PX4 Development Team. All rights reserved.
* Copyright (c) 2024 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,18 +31,67 @@
*
****************************************************************************/
/*
* This header defines the events::EventType type.
*/
#include "iis2mdc.h"
#include <drivers/device/i2c.h>
#pragma once
#include <uORB/topics/event.h>
namespace events
class IIS2MDC_I2C : public device::I2C
{
using EventType = event_s;
} // namespace events
public:
IIS2MDC_I2C(const I2CSPIDriverConfig &config);
virtual ~IIS2MDC_I2C() = default;
virtual int read(unsigned address, void *data, unsigned count) override;
virtual int write(unsigned address, void *data, unsigned count) override;
protected:
virtual int probe();
};
IIS2MDC_I2C::IIS2MDC_I2C(const I2CSPIDriverConfig &config) :
I2C(config)
{
}
int IIS2MDC_I2C::probe()
{
uint8_t data = 0;
if (read(IIS2MDC_ADDR_WHO_AM_I, &data, 1)) {
DEVICE_DEBUG("read_reg fail");
return -EIO;
}
if (data != IIS2MDC_WHO_AM_I) {
DEVICE_DEBUG("IIS2MDC bad ID: %02x", data);
return -EIO;
}
_retries = 1;
return OK;
}
int IIS2MDC_I2C::read(unsigned address, void *data, unsigned count)
{
uint8_t cmd = address;
return transfer(&cmd, 1, (uint8_t *)data, count);
}
int IIS2MDC_I2C::write(unsigned address, void *data, unsigned count)
{
uint8_t buf[32];
if (sizeof(buf) < (count + 1)) {
return -EIO;
}
buf[0] = address;
memcpy(&buf[1], data, count);
return transfer(&buf[0], count + 1, nullptr, 0);
}
device::Device *IIS2MDC_I2C_interface(const I2CSPIDriverConfig &config)
{
return new IIS2MDC_I2C(config);
}
@@ -0,0 +1,116 @@
/****************************************************************************
*
* Copyright (c) 2024 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#include "iis2mdc.h"
#include <px4_platform_common/module.h>
I2CSPIDriverBase *IIS2MDC::instantiate(const I2CSPIDriverConfig &config, int runtime_instance)
{
device::Device *interface = IIS2MDC_I2C_interface(config);
if (interface == nullptr) {
PX4_ERR("alloc failed");
return nullptr;
}
if (interface->init() != OK) {
delete interface;
PX4_DEBUG("no device on bus %i (devid 0x%lx)", config.bus, config.spi_devid);
return nullptr;
}
IIS2MDC *dev = new IIS2MDC(interface, config);
if (dev == nullptr) {
delete interface;
return nullptr;
}
if (OK != dev->init()) {
delete dev;
return nullptr;
}
return dev;
}
void IIS2MDC::print_usage()
{
PRINT_MODULE_USAGE_NAME("iis2mdc", "driver");
PRINT_MODULE_USAGE_SUBCATEGORY("magnetometer");
PRINT_MODULE_USAGE_COMMAND("start");
PRINT_MODULE_USAGE_PARAMS_I2C_SPI_DRIVER(true, false);
PRINT_MODULE_USAGE_PARAMS_I2C_ADDRESS(0x30);
PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
}
extern "C" int iis2mdc_main(int argc, char *argv[])
{
using ThisDriver = IIS2MDC;
int ch;
BusCLIArguments cli{true, false};
cli.i2c_address = 0x1E;
cli.default_i2c_frequency = 400000;
while ((ch = cli.getOpt(argc, argv, "R:")) != EOF) {
switch (ch) {
case 'R':
cli.rotation = (enum Rotation)atoi(cli.optArg());
break;
}
}
const char *verb = cli.optArg();
if (!verb) {
ThisDriver::print_usage();
return -1;
}
BusInstanceIterator iterator(MODULE_NAME, cli, DRV_MAG_DEVTYPE_IIS2MDC);
if (!strcmp(verb, "start")) {
return ThisDriver::module_start(cli, iterator);
}
if (!strcmp(verb, "stop")) {
return ThisDriver::module_stop(iterator);
}
if (!strcmp(verb, "status")) {
return ThisDriver::module_status(iterator);
}
ThisDriver::print_usage();
return -1;
}
@@ -87,14 +87,6 @@ void PowerMonitorSelectorAuterion::Run()
int ret_val = ina226_probe(i);
if (ret_val == PX4_OK) {
float current_shunt_value = 0.0f;
param_get(param_find("INA226_SHUNT"), &current_shunt_value);
if (fabsf(current_shunt_value - _sensors[i].shunt_value) > FLT_EPSILON) {
param_set(param_find("INA226_SHUNT"), &(_sensors[i].shunt_value));
}
char bus_number[4] = {0};
itoa(_sensors[i].bus_number, bus_number, 10);
const char *start_argv[] {
+16
View File
@@ -734,7 +734,15 @@ void RCInput::Run()
}
if (_crsf_telemetry) {
#if defined(RC_SERIAL_SINGLEWIRE_MANUAL_DUPLEX)
ioctl(_rcs_fd, TIOCSSINGLEWIRE, SER_SINGLEWIRE_ENABLED | SER_SINGLEWIRE_DIR_TX);
#endif
_crsf_telemetry->update(cycle_timestamp);
#if defined(RC_SERIAL_SINGLEWIRE_MANUAL_DUPLEX)
tcflush(_rcs_fd, TCIOFLUSH);
tcdrain(_rcs_fd); // Ensure TX FIFO is empty before swapping
ioctl(_rcs_fd, TIOCSSINGLEWIRE, SER_SINGLEWIRE_ENABLED | SER_SINGLEWIRE_DIR_RX);
#endif
}
}
}
@@ -787,7 +795,15 @@ void RCInput::Run()
}
if (_ghst_telemetry) {
#if defined(RC_SERIAL_SINGLEWIRE_MANUAL_DUPLEX)
ioctl(_rcs_fd, TIOCSSINGLEWIRE, SER_SINGLEWIRE_ENABLED | SER_SINGLEWIRE_DIR_TX);
#endif
_ghst_telemetry->update(cycle_timestamp);
#if defined(RC_SERIAL_SINGLEWIRE_MANUAL_DUPLEX)
tcflush(_rcs_fd, TCIOFLUSH);
tcdrain(_rcs_fd); // Ensure TX FIFO is empty before swapping
ioctl(_rcs_fd, TIOCSSINGLEWIRE, SER_SINGLEWIRE_ENABLED | SER_SINGLEWIRE_DIR_RX);
#endif
}
}
}
+1 -1
View File
@@ -34,4 +34,4 @@
add_subdirectory(bst)
add_subdirectory(frsky_telemetry)
add_subdirectory(hott)
#add_subdirectory(iridiumsbd)
add_subdirectory(iridiumsbd)
+12 -29
View File
@@ -235,7 +235,7 @@ int IridiumSBD::print_status()
PX4_INFO("RX session pending: %d", _rx_session_pending);
PX4_INFO("RX read pending: %d", _rx_read_pending);
PX4_INFO("Time since last signal check: %" PRId64, hrt_absolute_time() - _last_signal_check);
PX4_INFO("Last heartbeat: %" PRId64, _last_heartbeat);
PX4_INFO("Last heartbeat: %" PRId64, _last_at_ok_timestamp);
return 0;
}
@@ -333,6 +333,11 @@ void IridiumSBD::standby_loop(void)
}
}
if (!is_modem_responsive()) {
VERBOSE_INFO("MODEM IS NOT RENSPONSIVE");
return;
}
// check for incoming SBDRING, handled inside read_at_command()
read_at_command();
@@ -477,7 +482,6 @@ void IridiumSBD::sbdsession_loop(void)
_ring_pending = false;
_tx_session_pending = false;
_last_read_time = hrt_absolute_time();
_last_heartbeat = _last_read_time;
++_successful_sbd_sessions;
if (mt_queued > 0) {
@@ -498,8 +502,6 @@ void IridiumSBD::sbdsession_loop(void)
case 1:
VERBOSE_INFO("SBD SESSION: MO SUCCESS, MT FAIL");
_last_heartbeat = hrt_absolute_time();
// after a successful session reset the tx buffer
_tx_buf_write_idx = 0;
++_successful_sbd_sessions;
@@ -552,11 +554,6 @@ void IridiumSBD::start_csq(void)
_last_signal_check = hrt_absolute_time();
if (!is_modem_ready()) {
VERBOSE_INFO("UPDATE SIGNAL QUALITY: MODEM NOT READY!");
return;
}
write_at("AT+CSQ");
_new_state = SATCOM_STATE_CSQ;
}
@@ -571,11 +568,6 @@ void IridiumSBD::start_sbd_session(void)
VERBOSE_INFO("STARTING SBD SESSION");
}
if (!is_modem_ready()) {
VERBOSE_INFO("SBD SESSION: MODEM NOT READY!");
return;
}
if (_ring_pending) {
write_at("AT+SBDIXA");
@@ -610,8 +602,8 @@ void IridiumSBD::start_test(void)
printf("\n");
}
if (!is_modem_ready()) {
PX4_WARN("MODEM NOT READY!");
if (!is_modem_responsive()) {
PX4_WARN("MODEM NOT RENSPONSIVE!");
return;
}
@@ -718,11 +710,6 @@ ssize_t IridiumSBD::read(struct file *filp, char *buffer, size_t buflen)
void IridiumSBD::write_tx_buf()
{
if (!is_modem_ready()) {
VERBOSE_INFO("WRITE SBD: MODEM NOT READY!");
return;
}
pthread_mutex_lock(&_tx_buf_mutex);
char command[13];
@@ -779,11 +766,6 @@ void IridiumSBD::write_tx_buf()
void IridiumSBD::read_rx_buf(void)
{
if (!is_modem_ready()) {
VERBOSE_INFO("READ SBD: MODEM NOT READY!");
return;
}
pthread_mutex_lock(&_rx_buf_mutex);
@@ -949,11 +931,12 @@ satcom_uart_status IridiumSBD::open_uart(char *uart_name)
return SATCOM_UART_OK;
}
bool IridiumSBD::is_modem_ready(void)
bool IridiumSBD::is_modem_responsive(void)
{
write_at("AT");
if (read_at_command() == SATCOM_RESULT_OK) {
_last_at_ok_timestamp = hrt_absolute_time();
return true;
} else {
@@ -980,9 +963,9 @@ void IridiumSBD::publish_iridium_status()
{
bool need_to_publish = false;
if (_status.last_heartbeat != _last_heartbeat) {
if (_status.last_at_ok_timestamp != _last_at_ok_timestamp) {
need_to_publish = true;
_status.last_heartbeat = _last_heartbeat;
_status.last_at_ok_timestamp = _last_at_ok_timestamp;
}
if (_status.tx_buf_write_index != _tx_buf_write_idx) {
@@ -245,7 +245,7 @@ private:
/*
* Checks if the modem responds to the "AT" command
*/
bool is_modem_ready(void);
bool is_modem_responsive(void);
/*
* Get the poll state
@@ -321,7 +321,7 @@ private:
hrt_abstime _last_write_time = 0;
hrt_abstime _last_read_time = 0;
hrt_abstime _last_heartbeat = 0;
hrt_abstime _last_at_ok_timestamp = 0;
hrt_abstime _session_start_time = 0;
satcom_state _state = SATCOM_STATE_STANDBY;
+1 -1
View File
@@ -45,7 +45,7 @@ static uint16_t event_sequence{events::initial_event_sequence};
namespace events
{
void send(EventType &event)
void send(event_s &event)
{
event.timestamp = hrt_absolute_time();
+1 -1
View File
@@ -47,5 +47,5 @@
#define EVENTSIOCSEND _EVENTSIOC(1)
typedef struct eventiocsend {
events::EventType &event;
event_s &event;
} eventiocsend_t;
+1 -1
View File
@@ -44,7 +44,7 @@
namespace events
{
void send(EventType &event)
void send(event_s &event)
{
eventiocsend_t data = {event};
boardctl(EVENTSIOCSEND, reinterpret_cast<unsigned long>(&data));
+34 -23
View File
@@ -1109,7 +1109,7 @@ Commander::handle_command(const vehicle_command_s &cmd)
case vehicle_command_s::VEHICLE_CMD_CONTROL_HIGH_LATENCY: {
// if no high latency telemetry exists send a failed acknowledge
if (_high_latency_datalink_heartbeat > _boot_timestamp) {
if (_high_latency_datalink_timestamp < _boot_timestamp) {
cmd_result = vehicle_command_ack_s::VEHICLE_CMD_RESULT_FAILED;
mavlink_log_critical(&_mavlink_log_pub, "Control high latency failed! Telemetry unavailable\t");
events::send(events::ID("commander_ctrl_high_latency_failed"), {events::Log::Critical, events::LogInternal::Info},
@@ -2634,7 +2634,7 @@ int Commander::task_spawn(int argc, char *argv[])
_task_id = px4_task_spawn_cmd("commander",
SCHED_DEFAULT,
SCHED_PRIORITY_DEFAULT + 40,
3250,
PX4_STACK_ADJUSTED(3250),
(px4_main_t)&run_trampoline,
(char *const *)argv);
@@ -2672,6 +2672,28 @@ void Commander::enable_hil()
void Commander::dataLinkCheck()
{
// high latency data link
iridiumsbd_status_s iridium_status;
if (_iridiumsbd_status_sub.update(&iridium_status)) {
_high_latency_datalink_timestamp = iridium_status.last_at_ok_timestamp;
if (_vehicle_status.high_latency_data_link_lost &&
(_high_latency_datalink_timestamp > _high_latency_datalink_lost) &&
(_high_latency_datalink_regained == 0)
) {
_high_latency_datalink_regained = _high_latency_datalink_timestamp;
}
if (_vehicle_status.high_latency_data_link_lost &&
(_high_latency_datalink_regained != 0) &&
(hrt_elapsed_time(&_high_latency_datalink_regained) > (_param_com_hldl_reg_t.get() * 1_s))
) {
_vehicle_status.high_latency_data_link_lost = false;
_status_changed = true;
}
}
for (auto &telemetry_status : _telemetry_status_subs) {
telemetry_status_s telemetry;
@@ -2685,16 +2707,18 @@ void Commander::dataLinkCheck()
break;
case telemetry_status_s::LINK_TYPE_IRIDIUM: {
iridiumsbd_status_s iridium_status;
if (_iridiumsbd_status_sub.update(&iridium_status)) {
_high_latency_datalink_heartbeat = iridium_status.last_heartbeat;
if ((_high_latency_datalink_timestamp > 0) &&
(hrt_elapsed_time(&_high_latency_datalink_timestamp) > (_param_com_hldl_loss_t.get() * 1_s))) {
if (_vehicle_status.high_latency_data_link_lost) {
if (hrt_elapsed_time(&_high_latency_datalink_lost) > (_param_com_hldl_reg_t.get() * 1_s)) {
_vehicle_status.high_latency_data_link_lost = false;
_status_changed = true;
}
_high_latency_datalink_lost = _high_latency_datalink_timestamp;
_high_latency_datalink_regained = 0;
if (!_vehicle_status.high_latency_data_link_lost) {
_vehicle_status.high_latency_data_link_lost = true;
mavlink_log_critical(&_mavlink_log_pub, "High latency data link lost\t");
events::send(events::ID("commander_high_latency_lost"), events::Log::Critical, "High latency data link lost");
_status_changed = true;
}
}
@@ -2836,19 +2860,6 @@ void Commander::dataLinkCheck()
_vehicle_status.avoidance_system_valid = false;
}
}
// high latency data link loss failsafe
if (_high_latency_datalink_heartbeat > 0
&& hrt_elapsed_time(&_high_latency_datalink_heartbeat) > (_param_com_hldl_loss_t.get() * 1_s)) {
_high_latency_datalink_lost = hrt_absolute_time();
if (!_vehicle_status.high_latency_data_link_lost) {
_vehicle_status.high_latency_data_link_lost = true;
mavlink_log_critical(&_mavlink_log_pub, "High latency data link lost\t");
events::send(events::ID("commander_high_latency_lost"), events::Log::Critical, "High latency data link lost");
_status_changed = true;
}
}
}
void Commander::battery_status_check()
+2 -1
View File
@@ -246,8 +246,9 @@ private:
hrt_abstime _last_print_mode_reject_time{0}; ///< To remember when last notification was sent
hrt_abstime _high_latency_datalink_heartbeat{0};
hrt_abstime _high_latency_datalink_timestamp{0};
hrt_abstime _high_latency_datalink_lost{0};
hrt_abstime _high_latency_datalink_regained{0};
hrt_abstime _boot_timestamp{0};
hrt_abstime _last_disarmed_timestamp{0};
@@ -284,7 +284,7 @@ bool Report::report(bool is_armed, bool force)
// send all events
int offset = 0;
events::EventType event;
event_s event;
for (int i = 0; i < max_num_events && offset < _next_buffer_idx; ++i) {
EventBufferHeader *header = (EventBufferHeader *)(_event_buffer + offset);
@@ -376,7 +376,7 @@ bool Report::addEvent(uint32_t event_id, const events::LogLevels &log_levels, co
Args... args)
{
constexpr unsigned args_size = events::util::sizeofArguments(modes, args...);
static_assert(args_size <= sizeof(events::EventType::arguments), "Too many arguments");
static_assert(args_size <= sizeof(event_s::arguments), "Too many arguments");
unsigned total_size = sizeof(EventBufferHeader) + args_size;
if (total_size > sizeof(_event_buffer) - _next_buffer_idx) {
@@ -99,8 +99,12 @@ void EstimatorChecks::checkAndReport(const Context &context, Report &reporter)
}
}
param_t param_ekf2_en_handle = param_find_no_notification("EKF2_EN");
int32_t param_ekf2_en = 0;
param_get(param_find_no_notification("EKF2_EN"), &param_ekf2_en);
if (param_ekf2_en_handle != PARAM_INVALID) {
param_get(param_ekf2_en_handle, &param_ekf2_en);
}
if (missing_data && (param_ekf2_en == 1)) {
/* EVENT
@@ -48,13 +48,7 @@ void ImuConsistencyChecks::checkAndReport(const Context &context, Report &report
const float accel_inconsistency_m_s_s = imu.accel_inconsistency_m_s_s[i];
NavModes required_groups = NavModes::None;
if (accel_inconsistency_m_s_s > _param_com_arm_imu_acc.get()) {
required_groups = NavModes::All;
}
if (accel_inconsistency_m_s_s > _param_com_arm_imu_acc.get() * 0.8f) {
/* EVENT
* @description
* Check the calibration.
@@ -66,7 +60,7 @@ void ImuConsistencyChecks::checkAndReport(const Context &context, Report &report
* This check can be configured via <param>COM_ARM_IMU_ACC</param> parameter.
* </profile>
*/
reporter.armingCheckFailure<uint8_t, float, float>(required_groups, health_component_t::accel,
reporter.armingCheckFailure<uint8_t, float, float>(NavModes::All, health_component_t::accel,
events::ID("check_imu_accel_inconsistent"),
events::Log::Warning, "Accel {1} inconsistent", i, accel_inconsistency_m_s_s, _param_com_arm_imu_acc.get());
@@ -85,13 +79,7 @@ void ImuConsistencyChecks::checkAndReport(const Context &context, Report &report
const float gyro_inconsistency_rad_s = imu.gyro_inconsistency_rad_s[i];
NavModes required_groups = NavModes::None;
if (gyro_inconsistency_rad_s > _param_com_arm_imu_gyr.get()) {
required_groups = NavModes::All;
}
if (gyro_inconsistency_rad_s > _param_com_arm_imu_gyr.get() * 0.5f) {
/* EVENT
* @description
* Check the calibration.
@@ -103,7 +91,7 @@ void ImuConsistencyChecks::checkAndReport(const Context &context, Report &report
* This check can be configured via <param>COM_ARM_IMU_GYR</param> parameter.
* </profile>
*/
reporter.armingCheckFailure<uint8_t, float, float>(required_groups, health_component_t::gyro,
reporter.armingCheckFailure<uint8_t, float, float>(NavModes::All, health_component_t::gyro,
events::ID("check_imu_gyro_inconsistent"),
events::Log::Warning, "Gyro {1} inconsistent", i, gyro_inconsistency_rad_s, _param_com_arm_imu_gyr.get());
@@ -58,7 +58,7 @@ void ModeChecks::checkAndReport(const Context &context, Report &reporter)
* @description
* Wait until the estimator initialized
*/
reporter.armingCheckFailure((NavModes)reporter.failsafeFlags().mode_req_attitude, health_component_t::system,
reporter.armingCheckFailure((NavModes)reporter.failsafeFlags().mode_req_attitude, health_component_t::attitude_estimate,
events::ID("check_modes_attitude"),
events::Log::Critical, "No valid attitude estimate");
reporter.clearCanRunBits((NavModes)reporter.failsafeFlags().mode_req_attitude);
@@ -78,7 +78,7 @@ void ModeChecks::checkAndReport(const Context &context, Report &reporter)
if (local_position_modes != NavModes::None) {
/* EVENT
*/
reporter.armingCheckFailure(local_position_modes, health_component_t::system,
reporter.armingCheckFailure(local_position_modes, health_component_t::local_position_estimate,
events::ID("check_modes_local_pos"),
events::Log::Error, "No valid local position estimate");
reporter.clearCanRunBits(local_position_modes);
@@ -87,7 +87,8 @@ void ModeChecks::checkAndReport(const Context &context, Report &reporter)
if (reporter.failsafeFlags().global_position_invalid && reporter.failsafeFlags().mode_req_global_position != 0) {
/* EVENT
*/
reporter.armingCheckFailure((NavModes)reporter.failsafeFlags().mode_req_global_position, health_component_t::system,
reporter.armingCheckFailure((NavModes)reporter.failsafeFlags().mode_req_global_position,
health_component_t::global_position_estimate,
events::ID("check_modes_global_pos"),
events::Log::Error, "No valid global position estimate");
reporter.clearCanRunBits((NavModes)reporter.failsafeFlags().mode_req_global_position);
+36 -36
View File
@@ -116,111 +116,108 @@ endif()
set(EKF_LIBS)
set(EKF_SRCS)
list(APPEND EKF_SRCS
EKF/bias_estimator.cpp
EKF/control.cpp
EKF/covariance.cpp
EKF/ekf.cpp
EKF/ekf_helper.cpp
EKF/estimator_interface.cpp
EKF/fake_height_control.cpp
EKF/fake_pos_control.cpp
EKF/height_control.cpp
EKF/imu_down_sampler.cpp
EKF/output_predictor.cpp
EKF/velocity_fusion.cpp
EKF/position_fusion.cpp
EKF/yaw_fusion.cpp
EKF/zero_innovation_heading_update.cpp
EKF/imu_down_sampler/imu_down_sampler.cpp
EKF/aid_sources/fake_height_control.cpp
EKF/aid_sources/fake_pos_control.cpp
EKF/aid_sources/ZeroGyroUpdate.cpp
EKF/aid_sources/ZeroVelocityUpdate.cpp
EKF/aid_sources/zero_innovation_heading_update.cpp
)
if(CONFIG_EKF2_AIRSPEED)
list(APPEND EKF_SRCS EKF/airspeed_fusion.cpp)
list(APPEND EKF_SRCS EKF/aid_sources/airspeed/airspeed_fusion.cpp)
endif()
if(CONFIG_EKF2_AUX_GLOBAL_POSITION)
list(APPEND EKF_SRCS EKF/aux_global_position.cpp)
list(APPEND EKF_SRCS EKF/aid_sources/aux_global_position/aux_global_position.cpp)
endif()
if(CONFIG_EKF2_AUXVEL)
list(APPEND EKF_SRCS EKF/auxvel_fusion.cpp)
list(APPEND EKF_SRCS EKF/aid_sources/auxvel/auxvel_fusion.cpp)
endif()
if(CONFIG_EKF2_BAROMETER)
list(APPEND EKF_SRCS
EKF/baro_height_control.cpp
EKF/aid_sources/barometer/baro_height_control.cpp
)
endif()
if(CONFIG_EKF2_DRAG_FUSION)
list(APPEND EKF_SRCS EKF/drag_fusion.cpp)
list(APPEND EKF_SRCS EKF/aid_sources/drag/drag_fusion.cpp)
endif()
if(CONFIG_EKF2_EXTERNAL_VISION)
list(APPEND EKF_SRCS
EKF/ev_control.cpp
EKF/ev_height_control.cpp
EKF/ev_pos_control.cpp
EKF/ev_vel_control.cpp
EKF/ev_yaw_control.cpp
EKF/aid_sources/external_vision/ev_control.cpp
EKF/aid_sources/external_vision/ev_height_control.cpp
EKF/aid_sources/external_vision/ev_pos_control.cpp
EKF/aid_sources/external_vision/ev_vel_control.cpp
EKF/aid_sources/external_vision/ev_yaw_control.cpp
)
endif()
if(CONFIG_EKF2_GNSS)
list(APPEND EKF_SRCS
EKF/gnss_height_control.cpp
EKF/gps_checks.cpp
EKF/gps_control.cpp
EKF/aid_sources/gnss/gnss_height_control.cpp
EKF/aid_sources/gnss/gps_checks.cpp
EKF/aid_sources/gnss/gps_control.cpp
)
if(CONFIG_EKF2_GNSS_YAW)
list(APPEND EKF_SRCS EKF/aid_sources/gnss/gps_yaw_fusion.cpp)
endif()
list(APPEND EKF_LIBS yaw_estimator)
endif()
if(CONFIG_EKF2_GNSS_YAW)
list(APPEND EKF_SRCS EKF/gps_yaw_fusion.cpp)
endif()
if(CONFIG_EKF2_GRAVITY_FUSION)
list(APPEND EKF_SRCS EKF/gravity_fusion.cpp)
list(APPEND EKF_SRCS EKF/aid_sources/gravity/gravity_fusion.cpp)
endif()
if(CONFIG_EKF2_MAGNETOMETER)
list(APPEND EKF_SRCS
EKF/mag_3d_control.cpp
EKF/mag_control.cpp
EKF/mag_fusion.cpp
EKF/aid_sources/magnetometer/mag_3d_control.cpp
EKF/aid_sources/magnetometer/mag_control.cpp
EKF/aid_sources/magnetometer/mag_fusion.cpp
)
endif()
if(CONFIG_EKF2_OPTICAL_FLOW)
list(APPEND EKF_SRCS
EKF/optical_flow_control.cpp
EKF/optflow_fusion.cpp
EKF/aid_sources/optical_flow/optical_flow_control.cpp
EKF/aid_sources/optical_flow/optical_flow_fusion.cpp
)
endif()
if(CONFIG_EKF2_RANGE_FINDER)
list(APPEND EKF_SRCS
EKF/range_finder_consistency_check.cpp
EKF/range_height_control.cpp
EKF/sensor_range_finder.cpp
EKF/aid_sources/range_finder/range_finder_consistency_check.cpp
EKF/aid_sources/range_finder/range_height_control.cpp
EKF/aid_sources/range_finder/sensor_range_finder.cpp
)
endif()
if(CONFIG_EKF2_SIDESLIP)
list(APPEND EKF_SRCS EKF/sideslip_fusion.cpp)
list(APPEND EKF_SRCS EKF/aid_sources/sideslip/sideslip_fusion.cpp)
endif()
if(CONFIG_EKF2_TERRAIN)
list(APPEND EKF_SRCS EKF/terrain_estimator.cpp)
list(APPEND EKF_SRCS EKF/terrain_estimator/terrain_estimator.cpp)
endif()
add_subdirectory(EKF)
px4_add_module(
MODULE modules__ekf2
MAIN ekf2
@@ -260,7 +257,10 @@ px4_add_module(
EKF2Utility
px4_work_queue
world_magnetic_model
${EKF_LIBS}
bias_estimator
output_predictor
UNITY_BUILD
)
+38 -34
View File
@@ -31,109 +31,111 @@
#
############################################################################
add_subdirectory(bias_estimator)
add_subdirectory(output_predictor)
set(EKF_LIBS)
set(EKF_SRCS)
list(APPEND EKF_SRCS
bias_estimator.cpp
control.cpp
covariance.cpp
ekf.cpp
ekf_helper.cpp
estimator_interface.cpp
fake_height_control.cpp
fake_pos_control.cpp
height_control.cpp
imu_down_sampler.cpp
output_predictor.cpp
velocity_fusion.cpp
position_fusion.cpp
yaw_fusion.cpp
zero_innovation_heading_update.cpp
imu_down_sampler/imu_down_sampler.cpp
aid_sources/fake_height_control.cpp
aid_sources/fake_pos_control.cpp
aid_sources/ZeroGyroUpdate.cpp
aid_sources/ZeroVelocityUpdate.cpp
aid_sources/zero_innovation_heading_update.cpp
)
if(CONFIG_EKF2_AIRSPEED)
list(APPEND EKF_SRCS airspeed_fusion.cpp)
list(APPEND EKF_SRCS aid_sources/airspeed/airspeed_fusion.cpp)
endif()
if(CONFIG_EKF2_AUX_GLOBAL_POSITION)
list(APPEND EKF_SRCS aux_global_position.cpp)
list(APPEND EKF_SRCS aid_sources/aux_global_position/aux_global_position.cpp)
endif()
if(CONFIG_EKF2_AUXVEL)
list(APPEND EKF_SRCS auxvel_fusion.cpp)
list(APPEND EKF_SRCS aid_sources/auxvel/auxvel_fusion.cpp)
endif()
if(CONFIG_EKF2_BAROMETER)
list(APPEND EKF_SRCS
baro_height_control.cpp
aid_sources/barometer/baro_height_control.cpp
)
endif()
if(CONFIG_EKF2_DRAG_FUSION)
list(APPEND EKF_SRCS drag_fusion.cpp)
list(APPEND EKF_SRCS aid_sources/drag/drag_fusion.cpp)
endif()
if(CONFIG_EKF2_EXTERNAL_VISION)
list(APPEND EKF_SRCS
ev_control.cpp
ev_height_control.cpp
ev_pos_control.cpp
ev_vel_control.cpp
ev_yaw_control.cpp
aid_sources/external_vision/ev_control.cpp
aid_sources/external_vision/ev_height_control.cpp
aid_sources/external_vision/ev_pos_control.cpp
aid_sources/external_vision/ev_vel_control.cpp
aid_sources/external_vision/ev_yaw_control.cpp
)
endif()
if(CONFIG_EKF2_GNSS)
list(APPEND EKF_SRCS
gnss_height_control.cpp
gps_checks.cpp
gps_control.cpp
aid_sources/gnss/gnss_height_control.cpp
aid_sources/gnss/gps_checks.cpp
aid_sources/gnss/gps_control.cpp
)
if(CONFIG_EKF2_GNSS_YAW)
list(APPEND EKF_SRCS aid_sources/gnss/gps_yaw_fusion.cpp)
endif()
add_subdirectory(yaw_estimator)
list(APPEND EKF_LIBS yaw_estimator)
endif()
if(CONFIG_EKF2_GNSS_YAW)
list(APPEND EKF_SRCS gps_yaw_fusion.cpp)
endif()
if(CONFIG_EKF2_GRAVITY_FUSION)
list(APPEND EKF_SRCS gravity_fusion.cpp)
list(APPEND EKF_SRCS aid_sources/gravity/gravity_fusion.cpp)
endif()
if(CONFIG_EKF2_MAGNETOMETER)
list(APPEND EKF_SRCS
mag_3d_control.cpp
mag_control.cpp
mag_fusion.cpp
aid_sources/magnetometer/mag_3d_control.cpp
aid_sources/magnetometer/mag_control.cpp
aid_sources/magnetometer/mag_fusion.cpp
)
endif()
if(CONFIG_EKF2_OPTICAL_FLOW)
list(APPEND EKF_SRCS
optical_flow_control.cpp
optflow_fusion.cpp
aid_sources/optical_flow/optical_flow_control.cpp
aid_sources/optical_flow/optical_flow_fusion.cpp
)
endif()
if(CONFIG_EKF2_RANGE_FINDER)
list(APPEND EKF_SRCS
range_finder_consistency_check.cpp
range_height_control.cpp
sensor_range_finder.cpp
aid_sources/range_finder/range_finder_consistency_check.cpp
aid_sources/range_finder/range_height_control.cpp
aid_sources/range_finder/sensor_range_finder.cpp
)
endif()
if(CONFIG_EKF2_SIDESLIP)
list(APPEND EKF_SRCS sideslip_fusion.cpp)
list(APPEND EKF_SRCS aid_sources/sideslip/sideslip_fusion.cpp)
endif()
if(CONFIG_EKF2_TERRAIN)
list(APPEND EKF_SRCS terrain_estimator.cpp)
list(APPEND EKF_SRCS terrain_estimator/terrain_estimator.cpp)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
@@ -146,7 +148,9 @@ target_include_directories(ecl_EKF PUBLIC ${EKF_GENERATED_DERIVATION_INCLUDE_PAT
target_link_libraries(ecl_EKF
PRIVATE
bias_estimator
geo
output_predictor
world_magnetic_model
${EKF_LIBS}
)
@@ -33,7 +33,7 @@
#include "ekf.h"
#include "aux_global_position.hpp"
#include "aid_sources/aux_global_position/aux_global_position.hpp"
#if defined(CONFIG_EKF2_AUX_GLOBAL_POSITION) && defined(MODULE_NAME)
@@ -42,8 +42,8 @@
// WelfordMean for init?
// WelfordMean for rate
#include "common.h"
#include "RingBuffer.h"
#include "../../common.h"
#include "../../RingBuffer.h"
#if defined(CONFIG_EKF2_AUX_GLOBAL_POSITION) && defined(MODULE_NAME)
@@ -196,3 +196,39 @@ void Ekf::stopBaroHgtFusion()
_control_status.flags.baro_hgt = false;
}
}
#if defined(CONFIG_EKF2_BARO_COMPENSATION)
float Ekf::compensateBaroForDynamicPressure(const float baro_alt_uncompensated) const
{
if (_control_status.flags.wind && local_position_is_valid()) {
// calculate static pressure error = Pmeas - Ptruth
// model position error sensitivity as a body fixed ellipse with a different scale in the positive and
// negative X and Y directions. Used to correct baro data for positional errors
// Calculate airspeed in body frame
const Vector3f vel_imu_rel_body_ned = _R_to_earth * (_ang_rate_delayed_raw % _params.imu_pos_body);
const Vector3f velocity_earth = _state.vel - vel_imu_rel_body_ned;
const Vector3f wind_velocity_earth(_state.wind_vel(0), _state.wind_vel(1), 0.0f);
const Vector3f airspeed_earth = velocity_earth - wind_velocity_earth;
const Vector3f airspeed_body = _state.quat_nominal.rotateVectorInverse(airspeed_earth);
const Vector3f K_pstatic_coef(
airspeed_body(0) >= 0.f ? _params.static_pressure_coef_xp : _params.static_pressure_coef_xn,
airspeed_body(1) >= 0.f ? _params.static_pressure_coef_yp : _params.static_pressure_coef_yn,
_params.static_pressure_coef_z);
const Vector3f airspeed_squared = matrix::min(airspeed_body.emult(airspeed_body), sq(_params.max_correction_airspeed));
const float pstatic_err = 0.5f * _air_density * (airspeed_squared.dot(K_pstatic_coef));
// correct baro measurement using pressure error estimate and assuming sea level gravity
return baro_alt_uncompensated + pstatic_err / (_air_density * CONSTANTS_ONE_G);
}
// otherwise return the uncorrected baro measurement
return baro_alt_uncompensated;
}
#endif // CONFIG_EKF2_BARO_COMPENSATION
@@ -358,7 +358,6 @@ void Ekf::controlGpsYawFusion(const gnssSample &gps_sample)
&& !_gps_intermittent;
if (_control_status.flags.gps_yaw) {
if (continuing_conditions_passing) {
fuseGpsYaw(gps_sample.yaw_offset);
@@ -366,27 +365,14 @@ void Ekf::controlGpsYawFusion(const gnssSample &gps_sample)
const bool is_fusion_failing = isTimedOut(_aid_src_gnss_yaw.time_last_fuse, _params.reset_timeout_max);
if (is_fusion_failing) {
if (_nb_gps_yaw_reset_available > 0) {
// Data seems good, attempt a reset
resetYawToGps(gps_sample.yaw, gps_sample.yaw_offset);
stopGpsYawFusion();
if (_control_status.flags.in_air) {
_nb_gps_yaw_reset_available--;
}
} else if (starting_conditions_passing) {
// Data seems good, but previous reset did not fix the issue
// something else must be wrong, declare the sensor faulty and stop the fusion
_control_status.flags.gps_yaw_fault = true;
stopGpsYawFusion();
} else {
// A reset did not fix the issue but all the starting checks are not passing
// This could be a temporary issue, stop the fusion without declaring the sensor faulty
stopGpsYawFusion();
// Before takeoff, we do not want to continue to rely on the current heading
// if we had to stop the fusion
if (!_control_status.flags.in_air) {
ECL_INFO("clearing yaw alignment");
_control_status.flags.yaw_align = false;
}
// TODO: should we give a new reset credit when the fusion does not fail for some time?
}
} else {
@@ -397,14 +383,27 @@ void Ekf::controlGpsYawFusion(const gnssSample &gps_sample)
} else {
if (starting_conditions_passing) {
// Try to activate GPS yaw fusion
if (resetYawToGps(gps_sample.yaw, gps_sample.yaw_offset)) {
ECL_INFO("starting GPS yaw fusion");
const bool not_using_ne_aiding = !_control_status.flags.gps && !_control_status.flags.aux_gpos;
_aid_src_gnss_yaw.time_last_fuse = _time_delayed_us;
if (!_control_status.flags.in_air
|| !_control_status.flags.yaw_align
|| not_using_ne_aiding) {
// Reset before starting the fusion
if (resetYawToGps(gps_sample.yaw, gps_sample.yaw_offset)) {
_aid_src_gnss_yaw.time_last_fuse = _time_delayed_us;
_control_status.flags.gps_yaw = true;
_control_status.flags.yaw_align = true;
}
} else if (!_aid_src_gnss_yaw.innovation_rejected) {
// Do not force a reset but wait for the consistency check to pass
_control_status.flags.gps_yaw = true;
_control_status.flags.yaw_align = true;
fuseGpsYaw(gps_sample.yaw_offset);
}
_nb_gps_yaw_reset_available = 1;
if (_control_status.flags.gps_yaw) {
ECL_INFO("starting GPS yaw fusion");
}
}
}
@@ -424,15 +423,7 @@ void Ekf::stopGpsYawFusion()
_control_status.flags.gps_yaw = false;
resetEstimatorAidStatus(_aid_src_gnss_yaw);
// Before takeoff, we do not want to continue to rely on the current heading
// if we had to stop the fusion
if (!_control_status.flags.in_air) {
ECL_INFO("stopping GPS yaw fusion, clearing yaw alignment");
_control_status.flags.yaw_align = false;
} else {
ECL_INFO("stopping GPS yaw fusion");
}
ECL_INFO("stopping GPS yaw fusion");
}
}
#endif // CONFIG_EKF2_GNSS_YAW
@@ -42,7 +42,7 @@
#ifndef EKF_SENSOR_HPP
#define EKF_SENSOR_HPP
#include "common.h"
#include <cstdint>
namespace estimator
{
@@ -35,9 +35,10 @@
* @file range_finder_consistency_check.cpp
*/
#include "range_finder_consistency_check.hpp"
#include <aid_sources/range_finder/range_finder_consistency_check.hpp>
void RangeFinderConsistencyCheck::update(float dist_bottom, float dist_bottom_var, float vz, float vz_var, bool horizontal_motion, uint64_t time_us)
void RangeFinderConsistencyCheck::update(float dist_bottom, float dist_bottom_var, float vz, float vz_var,
bool horizontal_motion, uint64_t time_us)
{
if (horizontal_motion) {
_time_last_horizontal_motion = time_us;
@@ -55,7 +56,8 @@ void RangeFinderConsistencyCheck::update(float dist_bottom, float dist_bottom_va
const float vel_bottom = (dist_bottom - _dist_bottom_prev) / dt;
_innov = -vel_bottom - vz; // vel_bottom is +up while vz is +down
const float var = 2.f * dist_bottom_var / (dt * dt); // Variance of the time derivative of a random variable: var(dz/dt) = 2*var(z) / dt^2
// Variance of the time derivative of a random variable: var(dz/dt) = 2*var(z) / dt^2
const float var = 2.f * dist_bottom_var / (dt * dt);
_innov_var = var + vz_var;
const float normalized_innov_sq = (_innov * _innov) / _innov_var;
@@ -84,8 +86,9 @@ void RangeFinderConsistencyCheck::updateConsistency(float vz, uint64_t time_us)
}
} else {
if (_test_ratio < 1.f
&& ((time_us - _time_last_inconsistent_us) > _consistency_hyst_time_us)) {
if ((_test_ratio < 1.f)
&& ((time_us - _time_last_inconsistent_us) > _consistency_hyst_time_us)
) {
_is_kinematically_consistent = true;
}
}
@@ -64,13 +64,14 @@ void Ekf::controlRangeHeightFusion()
if (_control_status.flags.in_air) {
const bool horizontal_motion = _control_status.flags.fixed_wing
|| (sq(_state.vel(0)) + sq(_state.vel(1)) > fmaxf(P.trace<2>(State::vel.idx), 0.1f));
|| (sq(_state.vel(0)) + sq(_state.vel(1)) > fmaxf(P.trace<2>(State::vel.idx), 0.1f));
const float dist_dependant_var = sq(_params.range_noise_scaler * _range_sensor.getDistBottom());
const float var = sq(_params.range_noise) + dist_dependant_var;
_rng_consistency_check.setGate(_params.range_kin_consistency_gate);
_rng_consistency_check.update(_range_sensor.getDistBottom(), math::max(var, 0.001f), _state.vel(2), P(State::vel.idx + 2, State::vel.idx + 2), horizontal_motion, _time_delayed_us);
_rng_consistency_check.update(_range_sensor.getDistBottom(), math::max(var, 0.001f), _state.vel(2),
P(State::vel.idx + 2, State::vel.idx + 2), horizontal_motion, _time_delayed_us);
}
} else {
@@ -121,13 +122,15 @@ void Ekf::controlRangeHeightFusion()
}
// determine if we should use height aiding
const bool do_conditional_range_aid = (_params.rng_ctrl == static_cast<int32_t>(RngCtrl::CONDITIONAL)) && isConditionalRangeAidSuitable();
const bool do_conditional_range_aid = (_params.rng_ctrl == static_cast<int32_t>(RngCtrl::CONDITIONAL))
&& isConditionalRangeAidSuitable();
const bool continuing_conditions_passing = ((_params.rng_ctrl == static_cast<int32_t>(RngCtrl::ENABLED)) || do_conditional_range_aid)
&& measurement_valid
&& _range_sensor.isDataHealthy();
const bool starting_conditions_passing = continuing_conditions_passing
&& isNewestSampleRecent(_time_last_range_buffer_push, 2 * RNG_MAX_INTERVAL)
&& isNewestSampleRecent(_time_last_range_buffer_push, 2 * estimator::sensor::RNG_MAX_INTERVAL)
&& _range_sensor.isRegularlySendingData();
if (_control_status.flags.rng_hgt) {
@@ -165,13 +168,17 @@ void Ekf::controlRangeHeightFusion()
} else {
if (starting_conditions_passing) {
if ((_params.height_sensor_ref == static_cast<int32_t>(HeightSensor::RANGE)) && (_params.rng_ctrl == static_cast<int32_t>(RngCtrl::CONDITIONAL))) {
if ((_params.height_sensor_ref == static_cast<int32_t>(HeightSensor::RANGE))
&& (_params.rng_ctrl == static_cast<int32_t>(RngCtrl::CONDITIONAL))
) {
// Range finder is used while hovering to stabilize the height estimate. Don't reset but use it as height reference.
ECL_INFO("starting conditional %s height fusion", HGT_SRC_NAME);
_height_sensor_ref = HeightSensor::RANGE;
bias_est.setBias(_state.pos(2) + measurement);
} else if ((_params.height_sensor_ref == static_cast<int32_t>(HeightSensor::RANGE)) && (_params.rng_ctrl != static_cast<int32_t>(RngCtrl::CONDITIONAL))) {
} else if ((_params.height_sensor_ref == static_cast<int32_t>(HeightSensor::RANGE))
&& (_params.rng_ctrl != static_cast<int32_t>(RngCtrl::CONDITIONAL))
) {
// Range finder is the primary height source, the ground is now the datum used
// to compute the local vertical position
ECL_INFO("starting %s height fusion, resetting height", HGT_SRC_NAME);
@@ -193,7 +200,7 @@ void Ekf::controlRangeHeightFusion()
}
} else if (_control_status.flags.rng_hgt
&& !isNewestSampleRecent(_time_last_range_buffer_push, 2 * RNG_MAX_INTERVAL)) {
&& !isNewestSampleRecent(_time_last_range_buffer_push, 2 * estimator::sensor::RNG_MAX_INTERVAL)) {
// No data anymore. Stop until it comes back.
ECL_WARN("stopping %s height fusion, no data", HGT_SRC_NAME);
stopRngHgtFusion();
@@ -203,6 +210,7 @@ void Ekf::controlRangeHeightFusion()
bool Ekf::isConditionalRangeAidSuitable()
{
#if defined(CONFIG_EKF2_TERRAIN)
if (_control_status.flags.in_air
&& _range_sensor.isHealthy()
&& isTerrainEstimateValid()) {
@@ -236,6 +244,7 @@ bool Ekf::isConditionalRangeAidSuitable()
return is_in_range && is_hagl_stable && is_below_max_speed;
}
#endif // CONFIG_EKF2_TERRAIN
return false;
@@ -38,20 +38,22 @@
*
*/
#include "sensor_range_finder.hpp"
#include <aid_sources/range_finder/sensor_range_finder.hpp>
#include <lib/matrix/matrix/math.hpp>
namespace estimator
{
namespace sensor
{
void SensorRangeFinder::runChecks(const uint64_t current_time_us, const Dcmf &R_to_earth)
void SensorRangeFinder::runChecks(const uint64_t current_time_us, const matrix::Dcmf &R_to_earth)
{
updateSensorToEarthRotation(R_to_earth);
updateValidity(current_time_us);
}
void SensorRangeFinder::updateSensorToEarthRotation(const Dcmf &R_to_earth)
void SensorRangeFinder::updateSensorToEarthRotation(const matrix::Dcmf &R_to_earth)
{
// calculate 2,2 element of rotation matrix from sensor frame to earth frame
// this is required for use of range finder and flow data
@@ -114,7 +116,7 @@ inline bool SensorRangeFinder::isDataInRange() const
void SensorRangeFinder::updateStuckCheck()
{
if(!isStuckDetectorEnabled()){
if (!isStuckDetectorEnabled()) {
// Stuck detector disabled
_is_stuck = false;
return;
@@ -42,6 +42,7 @@
#define EKF_SENSOR_RANGE_FINDER_HPP
#include "Sensor.hpp"
#include <matrix/math.hpp>
namespace estimator
@@ -49,6 +50,14 @@ namespace estimator
namespace sensor
{
struct rangeSample {
uint64_t time_us{}; ///< timestamp of the measurement (uSec)
float rng{}; ///< range (distance to ground) measurement (m)
int8_t quality{}; ///< Signal quality in percent (0...100%), where 0 = invalid signal, 100 = perfect signal, and -1 = unknown signal quality.
};
static constexpr uint64_t RNG_MAX_INTERVAL = 200e3; ///< Maximum allowable time interval between range finder measurements (uSec)
class SensorRangeFinder : public Sensor
{
public:
@@ -0,0 +1,41 @@
############################################################################
#
# Copyright (c) 2024 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
add_library(bias_estimator
bias_estimator.cpp
bias_estimator.hpp
height_bias_estimator.hpp
position_bias_estimator.hpp
)
add_dependencies(bias_estimator prebuild_targets)
@@ -39,7 +39,7 @@
#define EKF_HEIGHT_BIAS_ESTIMATOR_HPP
#include "bias_estimator.hpp"
#include "common.h"
#include "../common.h"
class HeightBiasEstimator: public BiasEstimator
{
@@ -39,7 +39,6 @@
#define EKF_POSITION_BIAS_ESTIMATOR_HPP
#include "bias_estimator.hpp"
#include "common.h"
class PositionBiasEstimator
{
-7
View File
@@ -70,7 +70,6 @@ static constexpr uint64_t BARO_MAX_INTERVAL = 200e3; ///< Maximum allowable
static constexpr uint64_t EV_MAX_INTERVAL = 200e3; ///< Maximum allowable time interval between external vision system measurements (uSec)
static constexpr uint64_t GNSS_MAX_INTERVAL = 500e3; ///< Maximum allowable time interval between GNSS measurements (uSec)
static constexpr uint64_t GNSS_YAW_MAX_INTERVAL = 1500e3; ///< Maximum allowable time interval between GNSS yaw measurements (uSec)
static constexpr uint64_t RNG_MAX_INTERVAL = 200e3; ///< Maximum allowable time interval between range finder measurements (uSec)
static constexpr uint64_t MAG_MAX_INTERVAL = 500e3; ///< Maximum allowable time interval between magnetic field measurements (uSec)
// bad accelerometer detection and mitigation
@@ -197,12 +196,6 @@ struct baroSample {
bool reset{false};
};
struct rangeSample {
uint64_t time_us{}; ///< timestamp of the measurement (uSec)
float rng{}; ///< range (distance to ground) measurement (m)
int8_t quality{}; ///< Signal quality in percent (0...100%), where 0 = invalid signal, 100 = perfect signal, and -1 = unknown signal quality.
};
struct airspeedSample {
uint64_t time_us{}; ///< timestamp of the measurement (uSec)
float true_airspeed{}; ///< true airspeed measurement (m/sec)
+24 -2
View File
@@ -282,6 +282,25 @@ void Ekf::resetQuatCov(const Vector3f &rot_var_ned)
P.uncorrelateCovarianceSetVariance<State::quat_nominal.dof>(State::quat_nominal.idx, rot_var_ned);
}
void Ekf::resetGyroBiasCov()
{
// Zero the corresponding covariances and set
// variances to the values use for initial alignment
P.uncorrelateCovarianceSetVariance<State::gyro_bias.dof>(State::gyro_bias.idx, sq(_params.switch_on_gyro_bias));
}
void Ekf::resetGyroBiasZCov()
{
P.uncorrelateCovarianceSetVariance<1>(State::gyro_bias.idx + 2, sq(_params.switch_on_gyro_bias));
}
void Ekf::resetAccelBiasCov()
{
// Zero the corresponding covariances and set
// variances to the values use for initial alignment
P.uncorrelateCovarianceSetVariance<State::accel_bias.dof>(State::accel_bias.idx, sq(_params.switch_on_accel_bias));
}
#if defined(CONFIG_EKF2_MAGNETOMETER)
void Ekf::resetMagCov()
{
@@ -295,7 +314,10 @@ void Ekf::resetMagCov()
}
#endif // CONFIG_EKF2_MAGNETOMETER
void Ekf::resetGyroBiasZCov()
#if defined(CONFIG_EKF2_WIND)
void Ekf::resetWindCov()
{
P.uncorrelateCovarianceSetVariance<1>(State::gyro_bias.idx + 2, sq(_params.switch_on_gyro_bias));
// start with a small initial uncertainty to improve the initial estimate
P.uncorrelateCovarianceSetVariance<State::wind_vel.dof>(State::wind_vel.idx, sq(_params.initial_wind_uncertainty));
}
#endif // CONFIG_EKF2_WIND
+15 -14
View File
@@ -49,9 +49,9 @@
# include "yaw_estimator/EKFGSF_yaw.h"
#endif // CONFIG_EKF2_GNSS
#include "bias_estimator.hpp"
#include "height_bias_estimator.hpp"
#include "position_bias_estimator.hpp"
#include "bias_estimator/bias_estimator.hpp"
#include "bias_estimator/height_bias_estimator.hpp"
#include "bias_estimator/position_bias_estimator.hpp"
#include <ekf_derivation/generated/state.h>
@@ -63,7 +63,7 @@
#include "aid_sources/ZeroVelocityUpdate.hpp"
#if defined(CONFIG_EKF2_AUX_GLOBAL_POSITION)
# include "aux_global_position.hpp"
# include "aid_sources/aux_global_position/aux_global_position.hpp"
#endif // CONFIG_EKF2_AUX_GLOBAL_POSITION
enum class Likelihood { LOW, MEDIUM, HIGH };
@@ -265,12 +265,13 @@ public:
// get the 1-sigma horizontal and vertical velocity uncertainty
void get_ekf_vel_accuracy(float *ekf_evh, float *ekf_evv) const;
// get the vehicle control limits required by the estimator to keep within sensor limitations
// Returns the following vehicle control limits required by the estimator to keep within sensor limitations.
// vxy_max : Maximum ground relative horizontal speed (meters/sec). NaN when limiting is not needed.
// vz_max : Maximum ground relative vertical speed (meters/sec). NaN when limiting is not needed.
// hagl_min : Minimum height above ground (meters). NaN when limiting is not needed.
// hagl_max : Maximum height above ground (meters). NaN when limiting is not needed.
void get_ekf_ctrl_limits(float *vxy_max, float *vz_max, float *hagl_min, float *hagl_max) const;
// Reset all IMU bias states and covariances to initial alignment values.
void resetImuBias();
void resetGyroBias();
void resetGyroBiasCov();
@@ -390,7 +391,7 @@ public:
void get_innovation_test_status(uint16_t &status, float &mag, float &vel, float &pos, float &hgt, float &tas,
float &hagl, float &beta) const;
// return a bitmask integer that describes which state estimates can be used for flight control
// return a bitmask integer that describes which state estimates are valid
void get_ekf_soln_status(uint16_t *status) const;
HeightSensor getHeightSensorRef() const { return _height_sensor_ref; }
@@ -672,7 +673,6 @@ private:
# if defined(CONFIG_EKF2_GNSS_YAW)
estimator_aid_source1d_s _aid_src_gnss_yaw{};
uint8_t _nb_gps_yaw_reset_available{0}; ///< remaining number of resets allowed before switching to another aiding source
# endif // CONFIG_EKF2_GNSS_YAW
#endif // CONFIG_EKF2_GNSS
@@ -948,10 +948,6 @@ private:
// and a scalar innovation value
void fuse(const VectorState &K, float innovation);
#if defined(CONFIG_EKF2_BARO_COMPENSATION)
float compensateBaroForDynamicPressure(float baro_alt_uncompensated) const;
#endif // CONFIG_EKF2_BARO_COMPENSATION
// calculate the earth rotation vector from a given latitude
Vector3f calcEarthRateNED(float lat_rad) const;
@@ -1080,6 +1076,11 @@ private:
void stopBaroHgtFusion();
void updateGroundEffect();
# if defined(CONFIG_EKF2_BARO_COMPENSATION)
float compensateBaroForDynamicPressure(float baro_alt_uncompensated) const;
# endif // CONFIG_EKF2_BARO_COMPENSATION
#endif // CONFIG_EKF2_BAROMETER
#if defined(CONFIG_EKF2_GRAVITY_FUSION)
-123
View File
@@ -56,43 +56,6 @@ bool Ekf::isHeightResetRequired() const
return (continuous_bad_accel_hgt || hgt_fusion_timeout);
}
#if defined(CONFIG_EKF2_BARO_COMPENSATION)
float Ekf::compensateBaroForDynamicPressure(const float baro_alt_uncompensated) const
{
if (_control_status.flags.wind && local_position_is_valid()) {
// calculate static pressure error = Pmeas - Ptruth
// model position error sensitivity as a body fixed ellipse with a different scale in the positive and
// negative X and Y directions. Used to correct baro data for positional errors
// Calculate airspeed in body frame
const Vector3f vel_imu_rel_body_ned = _R_to_earth * (_ang_rate_delayed_raw % _params.imu_pos_body);
const Vector3f velocity_earth = _state.vel - vel_imu_rel_body_ned;
const Vector3f wind_velocity_earth(_state.wind_vel(0), _state.wind_vel(1), 0.0f);
const Vector3f airspeed_earth = velocity_earth - wind_velocity_earth;
const Vector3f airspeed_body = _state.quat_nominal.rotateVectorInverse(airspeed_earth);
const Vector3f K_pstatic_coef(
airspeed_body(0) >= 0.f ? _params.static_pressure_coef_xp : _params.static_pressure_coef_xn,
airspeed_body(1) >= 0.f ? _params.static_pressure_coef_yp : _params.static_pressure_coef_yn,
_params.static_pressure_coef_z);
const Vector3f airspeed_squared = matrix::min(airspeed_body.emult(airspeed_body), sq(_params.max_correction_airspeed));
const float pstatic_err = 0.5f * _air_density * (airspeed_squared.dot(K_pstatic_coef));
// correct baro measurement using pressure error estimate and assuming sea level gravity
return baro_alt_uncompensated + pstatic_err / (_air_density * CONSTANTS_ONE_G);
}
// otherwise return the uncorrected baro measurement
return baro_alt_uncompensated;
}
#endif // CONFIG_EKF2_BARO_COMPENSATION
// calculate the earth rotation vector
Vector3f Ekf::calcEarthRateNED(float lat_rad) const
{
return Vector3f(CONSTANTS_EARTH_SPIN_RATE * cosf(lat_rad),
@@ -235,7 +198,6 @@ void Ekf::get_ekf_lpos_accuracy(float *ekf_eph, float *ekf_epv) const
*ekf_epv = sqrtf(P(State::pos.idx + 2, State::pos.idx + 2));
}
// get the 1-sigma horizontal and vertical velocity uncertainty
void Ekf::get_ekf_vel_accuracy(float *ekf_evh, float *ekf_evv) const
{
float hvel_err = sqrtf(P.trace<2>(State::vel.idx));
@@ -276,13 +238,6 @@ void Ekf::get_ekf_vel_accuracy(float *ekf_evh, float *ekf_evv) const
*ekf_evv = sqrtf(P(State::vel.idx + 2, State::vel.idx + 2));
}
/*
Returns the following vehicle control limits required by the estimator to keep within sensor limitations.
vxy_max : Maximum ground relative horizontal speed (meters/sec). NaN when limiting is not needed.
vz_max : Maximum ground relative vertical speed (meters/sec). NaN when limiting is not needed.
hagl_min : Minimum height above ground (meters). NaN when limiting is not needed.
hagl_max : Maximum height above ground (meters). NaN when limiting is not needed.
*/
void Ekf::get_ekf_ctrl_limits(float *vxy_max, float *vz_max, float *hagl_min, float *hagl_max) const
{
// Do not require limiting by default
@@ -330,12 +285,6 @@ void Ekf::get_ekf_ctrl_limits(float *vxy_max, float *vz_max, float *hagl_min, fl
#endif // CONFIG_EKF2_RANGE_FINDER
}
void Ekf::resetImuBias()
{
resetGyroBias();
resetAccelBias();
}
void Ekf::resetGyroBias()
{
// Zero the gyro bias states
@@ -344,13 +293,6 @@ void Ekf::resetGyroBias()
resetGyroBiasCov();
}
void Ekf::resetGyroBiasCov()
{
// Zero the corresponding covariances and set
// variances to the values use for initial alignment
P.uncorrelateCovarianceSetVariance<State::gyro_bias.dof>(State::gyro_bias.idx, sq(_params.switch_on_gyro_bias));
}
void Ekf::resetAccelBias()
{
// Zero the accel bias states
@@ -359,18 +301,6 @@ void Ekf::resetAccelBias()
resetAccelBiasCov();
}
void Ekf::resetAccelBiasCov()
{
// Zero the corresponding covariances and set
// variances to the values use for initial alignment
P.uncorrelateCovarianceSetVariance<State::accel_bias.dof>(State::accel_bias.idx, sq(_params.switch_on_accel_bias));
}
// get EKF innovation consistency check status information comprising of:
// status - a bitmask integer containing the pass/fail status for each EKF measurement innovation consistency check
// Innovation Test Ratios - these are the ratio of the innovation to the acceptance threshold.
// A value > 1 indicates that the sensor measurement has exceeded the maximum acceptable level and has been rejected by the EKF
// Where a measurement type is a vector quantity, eg magnetometer, GPS position, etc, the maximum value is returned.
void Ekf::get_innovation_test_status(uint16_t &status, float &mag, float &vel, float &pos, float &hgt, float &tas,
float &hagl, float &beta) const
{
@@ -498,7 +428,6 @@ void Ekf::get_innovation_test_status(uint16_t &status, float &mag, float &vel, f
#endif // CONFIG_EKF2_SIDESLIP
}
// return a bitmask integer that describes which state estimates are valid
void Ekf::get_ekf_soln_status(uint16_t *status) const
{
ekf_solution_status_u soln_status{};
@@ -694,53 +623,6 @@ void Ekf::updateGroundEffect()
}
#endif // CONFIG_EKF2_BAROMETER
void Ekf::resetQuatStateYaw(float yaw, float yaw_variance)
{
// save a copy of the quaternion state for later use in calculating the amount of reset change
const Quatf quat_before_reset = _state.quat_nominal;
// update the yaw angle variance
if (PX4_ISFINITE(yaw_variance) && (yaw_variance > FLT_EPSILON)) {
P.uncorrelateCovarianceSetVariance<1>(2, yaw_variance);
}
// update transformation matrix from body to world frame using the current estimate
// update the rotation matrix using the new yaw value
_R_to_earth = updateYawInRotMat(yaw, Dcmf(_state.quat_nominal));
// calculate the amount that the quaternion has changed by
const Quatf quat_after_reset(_R_to_earth);
const Quatf q_error((quat_after_reset * quat_before_reset.inversed()).normalized());
// update quaternion states
_state.quat_nominal = quat_after_reset;
// add the reset amount to the output observer buffered data
_output_predictor.resetQuaternion(q_error);
#if defined(CONFIG_EKF2_EXTERNAL_VISION)
// update EV attitude error filter
if (_ev_q_error_initialized) {
const Quatf ev_q_error_updated = (q_error * _ev_q_error_filt.getState()).normalized();
_ev_q_error_filt.reset(ev_q_error_updated);
}
#endif // CONFIG_EKF2_EXTERNAL_VISION
// record the state change
if (_state_reset_status.reset_count.quat == _state_reset_count_prev.quat) {
_state_reset_status.quat_change = q_error;
} else {
// there's already a reset this update, accumulate total delta
_state_reset_status.quat_change = q_error * _state_reset_status.quat_change;
_state_reset_status.quat_change.normalize();
}
_state_reset_status.reset_count.quat++;
_time_last_heading_fuse = _time_delayed_us;
}
#if defined(CONFIG_EKF2_WIND)
void Ekf::resetWind()
{
@@ -764,11 +646,6 @@ void Ekf::resetWindToZero()
resetWindCov();
}
void Ekf::resetWindCov()
{
// start with a small initial uncertainty to improve the initial estimate
P.uncorrelateCovarianceSetVariance<State::wind_vel.dof>(State::wind_vel.idx, sq(_params.initial_wind_uncertainty));
}
#endif // CONFIG_EKF2_WIND
void Ekf::updateIMUBiasInhibit(const imuSample &imu_delayed)
+3 -3
View File
@@ -266,7 +266,7 @@ void EstimatorInterface::setAirspeedData(const airspeedSample &airspeed_sample)
#endif // CONFIG_EKF2_AIRSPEED
#if defined(CONFIG_EKF2_RANGE_FINDER)
void EstimatorInterface::setRangeData(const rangeSample &range_sample)
void EstimatorInterface::setRangeData(const sensor::rangeSample &range_sample)
{
if (!_initialised) {
return;
@@ -274,7 +274,7 @@ void EstimatorInterface::setRangeData(const rangeSample &range_sample)
// Allocate the required buffer size if not previously done
if (_range_buffer == nullptr) {
_range_buffer = new RingBuffer<rangeSample>(_obs_buffer_length);
_range_buffer = new RingBuffer<sensor::rangeSample>(_obs_buffer_length);
if (_range_buffer == nullptr || !_range_buffer->valid()) {
delete _range_buffer;
@@ -291,7 +291,7 @@ void EstimatorInterface::setRangeData(const rangeSample &range_sample)
// limit data rate to prevent data being lost
if (time_us >= static_cast<int64_t>(_range_buffer->get_newest().time_us + _min_obs_interval_us)) {
rangeSample range_sample_new{range_sample};
sensor::rangeSample range_sample_new{range_sample};
range_sample_new.time_us = time_us;
_range_buffer->push(range_sample_new);
+7 -7
View File
@@ -63,12 +63,12 @@
#include "common.h"
#include "RingBuffer.h"
#include "imu_down_sampler.hpp"
#include "output_predictor.h"
#include "imu_down_sampler/imu_down_sampler.hpp"
#include "output_predictor/output_predictor.h"
#if defined(CONFIG_EKF2_RANGE_FINDER)
# include "range_finder_consistency_check.hpp"
# include "sensor_range_finder.hpp"
# include "aid_sources/range_finder/range_finder_consistency_check.hpp"
# include "aid_sources/range_finder/sensor_range_finder.hpp"
#endif // CONFIG_EKF2_RANGE_FINDER
#include <lib/atmosphere/atmosphere.h>
@@ -107,7 +107,7 @@ public:
#endif // CONFIG_EKF2_AIRSPEED
#if defined(CONFIG_EKF2_RANGE_FINDER)
void setRangeData(const rangeSample &range_sample);
void setRangeData(const estimator::sensor::rangeSample &range_sample);
// set sensor limitations reported by the rangefinder
void set_rangefinder_limits(float min_distance, float max_distance)
@@ -115,7 +115,7 @@ public:
_range_sensor.setLimits(min_distance, max_distance);
}
const rangeSample &get_rng_sample_delayed() { return *(_range_sensor.getSampleAddress()); }
const estimator::sensor::rangeSample &get_rng_sample_delayed() { return *(_range_sensor.getSampleAddress()); }
#endif // CONFIG_EKF2_RANGE_FINDER
#if defined(CONFIG_EKF2_OPTICAL_FLOW)
@@ -356,7 +356,7 @@ protected:
#endif // CONFIG_EKF2_EXTERNAL_VISION
#if defined(CONFIG_EKF2_RANGE_FINDER)
RingBuffer<rangeSample> *_range_buffer{nullptr};
RingBuffer<sensor::rangeSample> *_range_buffer{nullptr};
uint64_t _time_last_range_buffer_push{0};
sensor::SensorRangeFinder _range_sensor{};
@@ -1,4 +1,4 @@
#include "imu_down_sampler.hpp"
#include "imu_down_sampler/imu_down_sampler.hpp"
#include <lib/mathlib/mathlib.h>
@@ -41,7 +41,7 @@
#include <mathlib/mathlib.h>
#include <matrix/math.hpp>
#include "common.h"
#include "../common.h"
using namespace estimator;
@@ -0,0 +1,39 @@
############################################################################
#
# Copyright (c) 2024 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
add_library(output_predictor
output_predictor.cpp
output_predictor.h
)
add_dependencies(output_predictor prebuild_targets)
@@ -1,6 +1,6 @@
/****************************************************************************
*
* Copyright (c) 2022 PX4. All rights reserved.
* Copyright (c) 2022-2024 PX4. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -1,6 +1,6 @@
/****************************************************************************
*
* Copyright (c) 2022 PX4. All rights reserved.
* Copyright (c) 2022-2024 PX4. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,8 +36,7 @@
#include <matrix/math.hpp>
#include "common.h"
#include "RingBuffer.h"
#include "../RingBuffer.h"
#include <lib/geo/geo.h>
@@ -37,7 +37,12 @@ import symforce
symforce.set_epsilon_to_symbol()
import symforce.symbolic as sf
from utils.derivation_utils import *
# generate_px4_function from derivation_utils in EKF/ekf_derivation/utils
import os, sys
derivation_utils_dir = os.path.dirname(os.path.abspath(__file__)) + "/../../python/ekf_derivation/utils"
sys.path.append(derivation_utils_dir)
import derivation_utils
def predict_opt_flow(
terrain_vpos: sf.Scalar,
@@ -49,7 +54,7 @@ def predict_opt_flow(
R_to_earth = sf.Rot3(sf.Quaternion(xyz=q_att[1:4], w=q_att[0])).to_rotation_matrix()
flow_pred = sf.V2()
dist = - (pos_z - terrain_vpos)
dist = add_epsilon_sign(dist, dist, epsilon)
dist = derivation_utils.add_epsilon_sign(dist, dist, epsilon)
flow_pred[0] = -v[1] / dist * R_to_earth[2, 2]
flow_pred[1] = v[0] / dist * R_to_earth[2, 2]
return flow_pred
@@ -90,5 +95,5 @@ def terr_est_compute_flow_y_innov_var_and_h(
return (innov_var, Hy[0, 0])
print("Derive terrain estimator equations...")
generate_px4_function(terr_est_compute_flow_xy_innov_var_and_hx, output_names=["innov_var", "H"])
generate_px4_function(terr_est_compute_flow_y_innov_var_and_h, output_names=["innov_var", "H"])
derivation_utils.generate_px4_function(terr_est_compute_flow_xy_innov_var_and_hx, output_names=["innov_var", "H"])
derivation_utils.generate_px4_function(terr_est_compute_flow_y_innov_var_and_h, output_names=["innov_var", "H"])

Some files were not shown because too many files have changed in this diff Show More