mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-05-24 21:27:34 +08:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| adbe15ee9e | |||
| 2f200d13e0 | |||
| c330aba875 | |||
| 09f066a73a | |||
| 6fd0e98a69 | |||
| e8e8a60ca8 | |||
| 8cc7c99b59 | |||
| 30ce560e3a | |||
| dcb1103299 |
@@ -223,7 +223,7 @@ def create_pdf_report(ulog: ULog, multi_instance: int, output_plot_filename: str
|
||||
data_plot.save()
|
||||
data_plot.close()
|
||||
|
||||
# plot innovation_check_flags summary
|
||||
# plot innovation flags summary
|
||||
data_plot = CheckFlagsPlot(
|
||||
status_flags_time, estimator_status_flags, [['reject_hor_vel', 'reject_hor_pos'], ['reject_ver_vel', 'reject_ver_pos',
|
||||
'reject_hagl'],
|
||||
|
||||
@@ -154,7 +154,6 @@
|
||||
*(.text._ZN3Ekf20updateIMUBiasInhibitERKN9estimator9imuSampleE)
|
||||
*(.text._ZN9Commander13dataLinkCheckEv)
|
||||
*(.text._ZN17FlightModeManager10switchTaskE15FlightTaskIndex)
|
||||
*(.text._ZNK3Ekf26get_innovation_test_statusERtRfS1_S1_S1_S1_S1_S1_)
|
||||
*(.text._ZN12PX4Gyroscope9set_scaleEf)
|
||||
*(.text._ZN12FailsafeBase6updateERKyRKNS_5StateEbbRK16failsafe_flags_s)
|
||||
*(.text._ZN18MavlinkStreamDebug4sendEv)
|
||||
|
||||
+7
-20
@@ -69,27 +69,14 @@ uint32 filter_fault_flags # Bitmask to indicate EKF internal faults
|
||||
|
||||
float32 pos_horiz_accuracy # 1-Sigma estimated horizontal position accuracy relative to the estimators origin (m)
|
||||
float32 pos_vert_accuracy # 1-Sigma estimated vertical position accuracy relative to the estimators origin (m)
|
||||
uint16 innovation_check_flags # Bitmask to indicate pass/fail status of innovation consistency checks
|
||||
# 0 - true if velocity observations have been rejected
|
||||
# 1 - true if horizontal position observations have been rejected
|
||||
# 2 - true if true if vertical position observations have been rejected
|
||||
# 3 - true if the X magnetometer observation has been rejected
|
||||
# 4 - true if the Y magnetometer observation has been rejected
|
||||
# 5 - true if the Z magnetometer observation has been rejected
|
||||
# 6 - true if the yaw observation has been rejected
|
||||
# 7 - true if the airspeed observation has been rejected
|
||||
# 8 - true if the synthetic sideslip observation has been rejected
|
||||
# 9 - true if the height above ground observation has been rejected
|
||||
# 10 - true if the X optical flow observation has been rejected
|
||||
# 11 - true if the Y optical flow observation has been rejected
|
||||
|
||||
float32 mag_test_ratio # ratio of the largest magnetometer innovation component to the innovation test limit
|
||||
float32 vel_test_ratio # ratio of the largest velocity innovation component to the innovation test limit
|
||||
float32 pos_test_ratio # ratio of the largest horizontal position innovation component to the innovation test limit
|
||||
float32 hgt_test_ratio # ratio of the vertical position innovation to the innovation test limit
|
||||
float32 tas_test_ratio # ratio of the true airspeed innovation to the innovation test limit
|
||||
float32 hagl_test_ratio # ratio of the height above ground innovation to the innovation test limit
|
||||
float32 beta_test_ratio # ratio of the synthetic sideslip innovation to the innovation test limit
|
||||
float32 mag_test_ratio # low-pass filtered ratio of the largest magnetometer innovation component to the innovation test limit
|
||||
float32 vel_test_ratio # low-pass filtered ratio of the largest velocity innovation component to the innovation test limit
|
||||
float32 pos_test_ratio # low-pass filtered ratio of the largest horizontal position innovation component to the innovation test limit
|
||||
float32 hgt_test_ratio # low-pass filtered ratio of the vertical position innovation to the innovation test limit
|
||||
float32 tas_test_ratio # low-pass filtered ratio of the true airspeed innovation to the innovation test limit
|
||||
float32 hagl_test_ratio # low-pass filtered ratio of the height above ground innovation to the innovation test limit
|
||||
float32 beta_test_ratio # low-pass filtered ratio of the synthetic sideslip innovation to the innovation test limit
|
||||
|
||||
uint16 solution_status_flags # Bitmask indicating which filter kinematic state outputs are valid for flight control use.
|
||||
# 0 - True if the attitude estimate is good
|
||||
|
||||
@@ -17,4 +17,4 @@ bool reset_integral # Reset roll/pitch/yaw integrals (navigation logic change)
|
||||
|
||||
bool fw_control_yaw_wheel # control heading with steering wheel (used for auto takeoff on runway)
|
||||
|
||||
# TOPICS vehicle_attitude_setpoint mc_virtual_attitude_setpoint fw_virtual_attitude_setpoint
|
||||
# TOPICS vehicle_attitude_setpoint mc_virtual_attitude_setpoint fw_virtual_attitude_setpoint vehicle_attitude_reference_setpoint fw_virtual_vehicle_attitude_reference_setpoint
|
||||
|
||||
@@ -5,6 +5,8 @@ float32 roll # [rad/s] roll rate setpoint
|
||||
float32 pitch # [rad/s] pitch rate setpoint
|
||||
float32 yaw # [rad/s] yaw rate setpoint
|
||||
|
||||
float32[3] accel_feedforward # [rad/s²] angular acceleration feedforward
|
||||
|
||||
# For clarification: For multicopters thrust_body[0] and thrust[1] are usually 0 and thrust[2] is the negative throttle demand.
|
||||
# For fixed wings thrust_x is the throttle demand and thrust_y, thrust_z will usually be zero.
|
||||
float32[3] thrust_body # Normalized thrust command in body NED frame [-1,1]
|
||||
|
||||
Submodule platforms/nuttx/NuttX/nuttx updated: f6ecf7c566...9583e2d9ce
@@ -241,7 +241,7 @@ void CrsfRc::Run()
|
||||
int32_t longitude = static_cast<int32_t>(round(sensor_gps.longitude_deg * 1e7));
|
||||
uint16_t groundspeed = sensor_gps.vel_d_m_s / 3.6f * 10.f;
|
||||
uint16_t gps_heading = math::degrees(sensor_gps.cog_rad) * 100.f;
|
||||
uint16_t altitude = static_cast<int16_t>(sensor_gps.altitude_msl_m * 1e3) + 1000;
|
||||
uint16_t altitude = static_cast<int16_t>(sensor_gps.altitude_msl_m) + 1000;
|
||||
uint8_t num_satellites = sensor_gps.satellites_used;
|
||||
this->SendTelemetryGps(latitude, longitude, groundspeed, gps_heading, altitude, num_satellites);
|
||||
}
|
||||
|
||||
@@ -41,8 +41,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <px4_platform_common/defines.h>
|
||||
#include <matrix/SquareMatrix.hpp>
|
||||
|
||||
#include "lib/matrix/matrix/math.hpp"
|
||||
|
||||
namespace math
|
||||
{
|
||||
@@ -150,9 +154,6 @@ public:
|
||||
// take a step forward from the last state (and input), update the filter states
|
||||
integrateStates(time_step, last_state_sample_, last_rate_sample_);
|
||||
|
||||
// instantaneous acceleration from current input / state
|
||||
filter_accel_ = calculateInstantaneousAcceleration(state_sample, rate_sample);
|
||||
|
||||
// store the current samples
|
||||
last_state_sample_ = state_sample;
|
||||
last_rate_sample_ = rate_sample;
|
||||
@@ -174,7 +175,7 @@ public:
|
||||
last_rate_sample_ = rate;
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
|
||||
// A conservative multiplier (>=2) on sample frequency to bound the maximum time step
|
||||
static constexpr float kSampleRateMultiplier = 4.0f;
|
||||
@@ -247,7 +248,7 @@ private:
|
||||
* @param[in] state_sample [units]
|
||||
* @param[in] rate_sample [units/s]
|
||||
*/
|
||||
void integrateStatesForwardEuler(const float time_step, const T &state_sample, const T &rate_sample)
|
||||
virtual void integrateStatesForwardEuler(const float time_step, const T &state_sample, const T &rate_sample)
|
||||
{
|
||||
// general notation for what follows:
|
||||
// c: continuous
|
||||
@@ -278,6 +279,9 @@ private:
|
||||
|
||||
// discrete state transition
|
||||
transitionStates(state_matrix, input_matrix, state_sample, rate_sample);
|
||||
|
||||
// instantaneous acceleration from current input / state
|
||||
filter_accel_ = calculateInstantaneousAcceleration(state_sample, rate_sample);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,6 +328,9 @@ private:
|
||||
|
||||
// discrete state transition
|
||||
transitionStates(state_matrix, input_matrix, state_sample, rate_sample);
|
||||
|
||||
// instantaneous acceleration from current input / state
|
||||
filter_accel_ = calculateInstantaneousAcceleration(state_sample, rate_sample);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -151,6 +151,8 @@ void AuxGlobalPosition::update(Ekf &ekf, const estimator::imuSample &imu_delayed
|
||||
#if defined(MODULE_NAME)
|
||||
aid_src.timestamp = hrt_absolute_time();
|
||||
_estimator_aid_src_aux_global_position_pub.publish(aid_src);
|
||||
|
||||
_test_ratio_filtered = math::max(fabsf(aid_src.test_ratio_filtered[0]), fabsf(aid_src.test_ratio_filtered[1]));
|
||||
#endif // MODULE_NAME
|
||||
|
||||
} else if ((_state != State::stopped) && isTimedOut(_time_last_buffer_push, imu_delayed.time_us, (uint64_t)5e6)) {
|
||||
|
||||
@@ -74,6 +74,8 @@ public:
|
||||
updateParams();
|
||||
}
|
||||
|
||||
float test_ratio_filtered() const { return _test_ratio_filtered; }
|
||||
|
||||
private:
|
||||
bool isTimedOut(uint64_t last_sensor_timestamp, uint64_t time_delayed_us, uint64_t timeout_period) const
|
||||
{
|
||||
@@ -106,6 +108,8 @@ private:
|
||||
|
||||
State _state{State::stopped};
|
||||
|
||||
float _test_ratio_filtered{INFINITY};
|
||||
|
||||
#if defined(MODULE_NAME)
|
||||
struct reset_counters_s {
|
||||
uint8_t lat_lon{};
|
||||
|
||||
@@ -245,6 +245,7 @@ void Ekf::controlMagFusion()
|
||||
|
||||
if (reset_heading) {
|
||||
_control_status.flags.yaw_align = true;
|
||||
resetAidSourceStatusZeroInnovation(aid_src);
|
||||
}
|
||||
|
||||
_control_status.flags.mag = true;
|
||||
|
||||
@@ -383,13 +383,17 @@ public:
|
||||
*counter = _state_reset_status.reset_count.quat;
|
||||
}
|
||||
|
||||
// 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 get_innovation_test_status(uint16_t &status, float &mag, float &vel, float &pos, float &hgt, float &tas,
|
||||
float &hagl, float &beta) const;
|
||||
float getHeadingInnovationTestRatio() const;
|
||||
|
||||
float getVelocityInnovationTestRatio() const;
|
||||
|
||||
float getHorizontalPositionInnovationTestRatio() const;
|
||||
float getVerticalPositionInnovationTestRatio() const;
|
||||
|
||||
float getAirspeedInnovationTestRatio() const;
|
||||
float getSyntheticSideslipInnovationTestRatio() const;
|
||||
|
||||
float getHeightAboveGroundInnovationTestRatio() const;
|
||||
|
||||
// return a bitmask integer that describes which state estimates are valid
|
||||
void get_ekf_soln_status(uint16_t *status) const;
|
||||
|
||||
@@ -301,131 +301,196 @@ void Ekf::resetAccelBias()
|
||||
resetAccelBiasCov();
|
||||
}
|
||||
|
||||
void Ekf::get_innovation_test_status(uint16_t &status, float &mag, float &vel, float &pos, float &hgt, float &tas,
|
||||
float &hagl, float &beta) const
|
||||
float Ekf::getHeadingInnovationTestRatio() const
|
||||
{
|
||||
// return the integer bitmask containing the consistency check pass/fail status
|
||||
status = _innov_check_fail_status.value;
|
||||
|
||||
// return the largest magnetometer innovation test ratio
|
||||
mag = 0.f;
|
||||
// return the largest heading innovation test ratio
|
||||
float test_ratio = 0.f;
|
||||
|
||||
#if defined(CONFIG_EKF2_MAGNETOMETER)
|
||||
if (_control_status.flags.mag_hdg ||_control_status.flags.mag_3D) {
|
||||
mag = math::max(mag, sqrtf(Vector3f(_aid_src_mag.test_ratio).max()));
|
||||
for (auto &test_ratio_filtered : _aid_src_mag.test_ratio_filtered) {
|
||||
test_ratio = math::max(test_ratio, fabsf(test_ratio_filtered));
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_EKF2_MAGNETOMETER
|
||||
|
||||
#if defined(CONFIG_EKF2_GNSS_YAW)
|
||||
if (_control_status.flags.gps_yaw) {
|
||||
mag = math::max(mag, sqrtf(_aid_src_gnss_yaw.test_ratio));
|
||||
test_ratio = math::max(test_ratio, fabsf(_aid_src_gnss_yaw.test_ratio_filtered));
|
||||
}
|
||||
#endif // CONFIG_EKF2_GNSS_YAW
|
||||
|
||||
#if defined(CONFIG_EKF2_EXTERNAL_VISION)
|
||||
if (_control_status.flags.ev_yaw) {
|
||||
mag = math::max(mag, sqrtf(_aid_src_ev_yaw.test_ratio));
|
||||
test_ratio = math::max(test_ratio, fabsf(_aid_src_ev_yaw.test_ratio_filtered));
|
||||
}
|
||||
#endif // CONFIG_EKF2_EXTERNAL_VISION
|
||||
|
||||
// return the largest velocity and position innovation test ratio
|
||||
vel = NAN;
|
||||
pos = NAN;
|
||||
return sqrtf(test_ratio);
|
||||
}
|
||||
|
||||
float Ekf::getVelocityInnovationTestRatio() const
|
||||
{
|
||||
// return the largest velocity innovation test ratio
|
||||
float test_ratio = -1.f;
|
||||
|
||||
#if defined(CONFIG_EKF2_GNSS)
|
||||
if (_control_status.flags.gps) {
|
||||
float gps_vel = sqrtf(Vector3f(_aid_src_gnss_vel.test_ratio).max());
|
||||
vel = math::max(gps_vel, FLT_MIN);
|
||||
|
||||
float gps_pos = sqrtf(Vector2f(_aid_src_gnss_pos.test_ratio).max());
|
||||
pos = math::max(gps_pos, FLT_MIN);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
test_ratio = math::max(test_ratio, fabsf(_aid_src_gnss_vel.test_ratio_filtered[i]));
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_EKF2_GNSS
|
||||
|
||||
#if defined(CONFIG_EKF2_EXTERNAL_VISION)
|
||||
if (_control_status.flags.ev_vel) {
|
||||
float ev_vel = sqrtf(Vector3f(_aid_src_ev_vel.test_ratio).max());
|
||||
vel = math::max(vel, ev_vel, FLT_MIN);
|
||||
}
|
||||
|
||||
if (_control_status.flags.ev_pos) {
|
||||
float ev_pos = sqrtf(Vector2f(_aid_src_ev_pos.test_ratio).max());
|
||||
pos = math::max(pos, ev_pos, FLT_MIN);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
test_ratio = math::max(test_ratio, fabsf(_aid_src_ev_vel.test_ratio_filtered[i]));
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_EKF2_EXTERNAL_VISION
|
||||
|
||||
#if defined(CONFIG_EKF2_OPTICAL_FLOW)
|
||||
if (isOnlyActiveSourceOfHorizontalAiding(_control_status.flags.opt_flow)) {
|
||||
float of_vel = sqrtf(Vector2f(_aid_src_optical_flow.test_ratio).max());
|
||||
vel = math::max(of_vel, FLT_MIN);
|
||||
for (auto &test_ratio_filtered : _aid_src_optical_flow.test_ratio_filtered) {
|
||||
test_ratio = math::max(test_ratio, fabsf(test_ratio_filtered));
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_EKF2_OPTICAL_FLOW
|
||||
|
||||
if (PX4_ISFINITE(test_ratio) && (test_ratio >= 0.f)) {
|
||||
return sqrtf(test_ratio);
|
||||
}
|
||||
|
||||
return NAN;
|
||||
}
|
||||
|
||||
float Ekf::getHorizontalPositionInnovationTestRatio() const
|
||||
{
|
||||
// return the largest position innovation test ratio
|
||||
float test_ratio = -1.f;
|
||||
|
||||
#if defined(CONFIG_EKF2_GNSS)
|
||||
if (_control_status.flags.gps) {
|
||||
for (auto &test_ratio_filtered : _aid_src_gnss_pos.test_ratio_filtered) {
|
||||
test_ratio = math::max(test_ratio, fabsf(test_ratio_filtered));
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_EKF2_GNSS
|
||||
|
||||
#if defined(CONFIG_EKF2_EXTERNAL_VISION)
|
||||
if (_control_status.flags.ev_pos) {
|
||||
for (auto &test_ratio_filtered : _aid_src_ev_pos.test_ratio_filtered) {
|
||||
test_ratio = math::max(test_ratio, fabsf(test_ratio_filtered));
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_EKF2_EXTERNAL_VISION
|
||||
|
||||
#if defined(CONFIG_EKF2_AUX_GLOBAL_POSITION) && defined(MODULE_NAME)
|
||||
if (_control_status.flags.aux_gpos) {
|
||||
test_ratio = math::max(test_ratio, fabsf(_aux_global_position.test_ratio_filtered()));
|
||||
}
|
||||
#endif // CONFIG_EKF2_AUX_GLOBAL_POSITION
|
||||
|
||||
if (PX4_ISFINITE(test_ratio) && (test_ratio >= 0.f)) {
|
||||
return sqrtf(test_ratio);
|
||||
}
|
||||
|
||||
return NAN;
|
||||
}
|
||||
|
||||
float Ekf::getVerticalPositionInnovationTestRatio() const
|
||||
{
|
||||
// return the combined vertical position innovation test ratio
|
||||
float hgt_sum = 0.f;
|
||||
int n_hgt_sources = 0;
|
||||
|
||||
#if defined(CONFIG_EKF2_BAROMETER)
|
||||
if (_control_status.flags.baro_hgt) {
|
||||
hgt_sum += sqrtf(_aid_src_baro_hgt.test_ratio);
|
||||
hgt_sum += sqrtf(fabsf(_aid_src_baro_hgt.test_ratio_filtered));
|
||||
n_hgt_sources++;
|
||||
}
|
||||
#endif // CONFIG_EKF2_BAROMETER
|
||||
|
||||
#if defined(CONFIG_EKF2_GNSS)
|
||||
if (_control_status.flags.gps_hgt) {
|
||||
hgt_sum += sqrtf(_aid_src_gnss_hgt.test_ratio);
|
||||
hgt_sum += sqrtf(fabsf(_aid_src_gnss_hgt.test_ratio_filtered));
|
||||
n_hgt_sources++;
|
||||
}
|
||||
#endif // CONFIG_EKF2_GNSS
|
||||
|
||||
#if defined(CONFIG_EKF2_RANGE_FINDER)
|
||||
if (_control_status.flags.rng_hgt) {
|
||||
hgt_sum += sqrtf(_aid_src_rng_hgt.test_ratio);
|
||||
hgt_sum += sqrtf(fabsf(_aid_src_rng_hgt.test_ratio_filtered));
|
||||
n_hgt_sources++;
|
||||
}
|
||||
#endif // CONFIG_EKF2_RANGE_FINDER
|
||||
|
||||
#if defined(CONFIG_EKF2_EXTERNAL_VISION)
|
||||
if (_control_status.flags.ev_hgt) {
|
||||
hgt_sum += sqrtf(_aid_src_ev_hgt.test_ratio);
|
||||
hgt_sum += sqrtf(fabsf(_aid_src_ev_hgt.test_ratio_filtered));
|
||||
n_hgt_sources++;
|
||||
}
|
||||
#endif // CONFIG_EKF2_EXTERNAL_VISION
|
||||
|
||||
if (n_hgt_sources > 0) {
|
||||
hgt = math::max(hgt_sum / static_cast<float>(n_hgt_sources), FLT_MIN);
|
||||
|
||||
} else {
|
||||
hgt = NAN;
|
||||
return math::max(hgt_sum / static_cast<float>(n_hgt_sources), FLT_MIN);
|
||||
}
|
||||
|
||||
return NAN;
|
||||
}
|
||||
|
||||
float Ekf::getAirspeedInnovationTestRatio() const
|
||||
{
|
||||
#if defined(CONFIG_EKF2_AIRSPEED)
|
||||
// return the airspeed fusion innovation test ratio
|
||||
tas = sqrtf(_aid_src_airspeed.test_ratio);
|
||||
if (_control_status.flags.fuse_aspd) {
|
||||
// return the airspeed fusion innovation test ratio
|
||||
return sqrtf(fabsf(_aid_src_airspeed.test_ratio_filtered));
|
||||
}
|
||||
#endif // CONFIG_EKF2_AIRSPEED
|
||||
|
||||
hagl = NAN;
|
||||
return NAN;
|
||||
}
|
||||
|
||||
float Ekf::getSyntheticSideslipInnovationTestRatio() const
|
||||
{
|
||||
#if defined(CONFIG_EKF2_SIDESLIP)
|
||||
if (_control_status.flags.fuse_beta) {
|
||||
// return the synthetic sideslip innovation test ratio
|
||||
return sqrtf(fabsf(_aid_src_sideslip.test_ratio_filtered));
|
||||
}
|
||||
#endif // CONFIG_EKF2_SIDESLIP
|
||||
|
||||
return NAN;
|
||||
}
|
||||
|
||||
float Ekf::getHeightAboveGroundInnovationTestRatio() const
|
||||
{
|
||||
float test_ratio = -1.f;
|
||||
|
||||
#if defined(CONFIG_EKF2_TERRAIN)
|
||||
# if defined(CONFIG_EKF2_RANGE_FINDER)
|
||||
if (_hagl_sensor_status.flags.range_finder) {
|
||||
// return the terrain height innovation test ratio
|
||||
hagl = sqrtf(_aid_src_terrain_range_finder.test_ratio);
|
||||
test_ratio = math::max(test_ratio, fabsf(_aid_src_terrain_range_finder.test_ratio_filtered));
|
||||
}
|
||||
#endif // CONFIG_EKF2_RANGE_FINDER
|
||||
|
||||
# if defined(CONFIG_EKF2_OPTICAL_FLOW)
|
||||
if (_hagl_sensor_status.flags.flow) {
|
||||
// return the terrain height innovation test ratio
|
||||
hagl = sqrtf(math::max(_aid_src_terrain_optical_flow.test_ratio[0], _aid_src_terrain_optical_flow.test_ratio[1]));
|
||||
for (auto &test_ratio_filtered : _aid_src_terrain_optical_flow.test_ratio_filtered) {
|
||||
test_ratio = math::max(test_ratio, fabsf(test_ratio_filtered));
|
||||
}
|
||||
}
|
||||
# endif // CONFIG_EKF2_OPTICAL_FLOW
|
||||
#endif // CONFIG_EKF2_TERRAIN
|
||||
|
||||
#if defined(CONFIG_EKF2_SIDESLIP)
|
||||
// return the synthetic sideslip innovation test ratio
|
||||
beta = sqrtf(_aid_src_sideslip.test_ratio);
|
||||
#endif // CONFIG_EKF2_SIDESLIP
|
||||
if (PX4_ISFINITE(test_ratio) && (test_ratio >= 0.f)) {
|
||||
return sqrtf(test_ratio);
|
||||
}
|
||||
|
||||
return NAN;
|
||||
}
|
||||
|
||||
void Ekf::get_ekf_soln_status(uint16_t *status) const
|
||||
|
||||
@@ -1802,15 +1802,13 @@ void EKF2::PublishStatus(const hrt_abstime ×tamp)
|
||||
status.control_mode_flags = _ekf.control_status().value;
|
||||
status.filter_fault_flags = _ekf.fault_status().value;
|
||||
|
||||
uint16_t innov_check_flags_temp = 0;
|
||||
_ekf.get_innovation_test_status(innov_check_flags_temp, status.mag_test_ratio,
|
||||
status.vel_test_ratio, status.pos_test_ratio,
|
||||
status.hgt_test_ratio, status.tas_test_ratio,
|
||||
status.hagl_test_ratio, status.beta_test_ratio);
|
||||
|
||||
// Bit mismatch between ecl and Firmware, combine the 2 first bits to preserve msg definition
|
||||
// TODO: legacy use only, those flags are also in estimator_status_flags
|
||||
status.innovation_check_flags = (innov_check_flags_temp >> 1) | (innov_check_flags_temp & 0x1);
|
||||
status.mag_test_ratio = _ekf.getHeadingInnovationTestRatio();
|
||||
status.vel_test_ratio = _ekf.getVelocityInnovationTestRatio();
|
||||
status.pos_test_ratio = _ekf.getHorizontalPositionInnovationTestRatio();
|
||||
status.hgt_test_ratio = _ekf.getVerticalPositionInnovationTestRatio();
|
||||
status.tas_test_ratio = _ekf.getAirspeedInnovationTestRatio();
|
||||
status.hagl_test_ratio = _ekf.getHeightAboveGroundInnovationTestRatio();
|
||||
status.beta_test_ratio = _ekf.getSyntheticSideslipInnovationTestRatio();
|
||||
|
||||
_ekf.get_ekf_lpos_accuracy(&status.pos_horiz_accuracy, &status.pos_vert_accuracy);
|
||||
_ekf.get_ekf_soln_status(&status.solution_status_flags);
|
||||
|
||||
@@ -36,8 +36,8 @@ px4_add_module(
|
||||
MAIN fw_att_control
|
||||
SRCS
|
||||
FixedwingAttitudeControl.cpp
|
||||
FixedwingAttitudeControl.hpp
|
||||
|
||||
att_ref_model.cpp
|
||||
fw_pitch_controller.cpp
|
||||
fw_roll_controller.cpp
|
||||
fw_wheel_controller.cpp
|
||||
|
||||
@@ -119,16 +119,6 @@ FixedwingAttitudeControl::vehicle_manual_poll(const float yaw_body)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FixedwingAttitudeControl::vehicle_attitude_setpoint_poll()
|
||||
{
|
||||
if (_att_sp_sub.update(&_att_sp)) {
|
||||
_rates_sp.thrust_body[0] = _att_sp.thrust_body[0];
|
||||
_rates_sp.thrust_body[1] = _att_sp.thrust_body[1];
|
||||
_rates_sp.thrust_body[2] = _att_sp.thrust_body[2];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FixedwingAttitudeControl::vehicle_land_detected_poll()
|
||||
{
|
||||
@@ -260,7 +250,16 @@ void FixedwingAttitudeControl::Run()
|
||||
|
||||
vehicle_manual_poll(euler_angles.psi());
|
||||
|
||||
vehicle_attitude_setpoint_poll();
|
||||
// attitude setpoint poll
|
||||
_reference_model.update();
|
||||
|
||||
_att_sp = _reference_model.getOutput();
|
||||
matrix::Vector2f vel_feedforward = _reference_model.getRateFeedforward();
|
||||
matrix::Vector2f acc_feedforward = _reference_model.getTorqueFeedforward();
|
||||
|
||||
_rates_sp.thrust_body[0] = _att_sp.thrust_body[0];
|
||||
_rates_sp.thrust_body[1] = _att_sp.thrust_body[1];
|
||||
_rates_sp.thrust_body[2] = _att_sp.thrust_body[2];
|
||||
|
||||
// vehicle status update must be before the vehicle_control_mode poll, otherwise rate sp are not published during whole transition
|
||||
_vehicle_status_sub.update(&_vehicle_status);
|
||||
@@ -371,10 +370,14 @@ void FixedwingAttitudeControl::Run()
|
||||
}
|
||||
|
||||
/* Publish the rate setpoint for analysis once available */
|
||||
_rates_sp.roll = body_rates_setpoint(0);
|
||||
_rates_sp.pitch = body_rates_setpoint(1);
|
||||
_rates_sp.roll = body_rates_setpoint(0) + vel_feedforward(0);
|
||||
_rates_sp.pitch = body_rates_setpoint(1) + vel_feedforward(1);
|
||||
_rates_sp.yaw = body_rates_setpoint(2);
|
||||
|
||||
_rates_sp.accel_feedforward[0] = acc_feedforward(0);
|
||||
_rates_sp.accel_feedforward[1] = acc_feedforward(1);
|
||||
_rates_sp.accel_feedforward[2] = 0.f;
|
||||
|
||||
_rates_sp.timestamp = hrt_absolute_time();
|
||||
|
||||
_rate_sp_pub.publish(_rates_sp);
|
||||
@@ -404,6 +407,7 @@ void FixedwingAttitudeControl::Run()
|
||||
} else {
|
||||
// full manual
|
||||
_wheel_ctrl.reset_integrator();
|
||||
_reference_model.reset();
|
||||
|
||||
_landing_gear_wheel.normalized_wheel_setpoint = PX4_ISFINITE(_manual_control_setpoint.yaw) ?
|
||||
_manual_control_setpoint.yaw : 0.f;
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include "att_ref_model.h"
|
||||
#include "fw_pitch_controller.h"
|
||||
#include "fw_roll_controller.h"
|
||||
#include "fw_wheel_controller.h"
|
||||
@@ -98,7 +99,6 @@ private:
|
||||
|
||||
uORB::SubscriptionInterval _parameter_update_sub{ORB_ID(parameter_update), 1_s};
|
||||
|
||||
uORB::Subscription _att_sp_sub{ORB_ID(vehicle_attitude_setpoint)}; /**< vehicle attitude setpoint */
|
||||
uORB::Subscription _autotune_attitude_control_status_sub{ORB_ID(autotune_attitude_control_status)};
|
||||
uORB::Subscription _local_pos_sub{ORB_ID(vehicle_local_position)}; /**< local position subscription */
|
||||
uORB::Subscription _manual_control_setpoint_sub{ORB_ID(manual_control_setpoint)}; /**< notification of manual control updates */
|
||||
@@ -165,9 +165,10 @@ private:
|
||||
YawController _yaw_ctrl;
|
||||
WheelController _wheel_ctrl;
|
||||
|
||||
FixedwingAttitudeReferenceModel _reference_model;
|
||||
|
||||
void parameters_update();
|
||||
void vehicle_manual_poll(const float yaw_body);
|
||||
void vehicle_attitude_setpoint_poll();
|
||||
void vehicle_land_detected_poll();
|
||||
float get_airspeed_constrained();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
#include "att_ref_model.h"
|
||||
|
||||
#include <px4_platform_common/log.h>
|
||||
|
||||
#include <lib/mathlib/mathlib.h>
|
||||
#include "lib/slew_rate/SlewRate.hpp"
|
||||
|
||||
float REFERENCE_MODEL_DAMPING{1.f};
|
||||
|
||||
FixedwingAttitudeReferenceModel::FixedwingAttitudeReferenceModel() :
|
||||
ModuleParams(nullptr)
|
||||
{
|
||||
parameters_update();
|
||||
}
|
||||
|
||||
void FixedwingAttitudeReferenceModel::update()
|
||||
{
|
||||
parameters_update();
|
||||
|
||||
/* We check if the attitude setpoint topic got updated externally, put in throughput mode,
|
||||
if attitude reference got updated, but into filter mode. If none, keep the current mode.
|
||||
If both put throughput mode for safety. */
|
||||
_att_sp_sub.update();
|
||||
|
||||
if (_att_sp_sub.get().timestamp > _last_att_setpoint_timestamp) {
|
||||
if (_mode == ModelMode::MODELMODE_FILTERING) {
|
||||
PX4_INFO("FixedWingAttitudeReferenceModel: Switch to throughput mode");
|
||||
}
|
||||
|
||||
_mode = ModelMode::MODELMODE_THROUGHPUT;
|
||||
|
||||
} else if (_att_ref_sp_sub.updated()) {
|
||||
_att_ref_sp_sub.update();
|
||||
|
||||
if (_mode == ModelMode::MODELMODE_THROUGHPUT) {
|
||||
PX4_INFO("FixedWingAttitudeReferenceModel: Switch to filtering mode");
|
||||
}
|
||||
|
||||
_mode = ModelMode::MODELMODE_FILTERING;
|
||||
|
||||
}
|
||||
|
||||
hrt_abstime now = hrt_absolute_time();
|
||||
|
||||
_attitiude_rate_feedforward_output = matrix::Vector2f{};
|
||||
_attitiude_torque_feedforward_output = matrix::Vector2f{};
|
||||
|
||||
if (_mode == ModelMode::MODELMODE_FILTERING) {
|
||||
|
||||
if (!_is_initialized) {
|
||||
|
||||
_is_initialized = true;
|
||||
_roll_ref_model.reset(_att_ref_sp_sub.get().roll_body);
|
||||
_pitch_ref_model.reset(_att_ref_sp_sub.get().pitch_body);
|
||||
|
||||
} else {
|
||||
if (_att_ref_sp_sub.get().timestamp > _last_update_timestamp) {
|
||||
_roll_ref_model.update(static_cast<float>(_att_ref_sp_sub.get().timestamp - _last_update_timestamp) / 1_s,
|
||||
_last_attitude_reference_setpoint.roll_body);
|
||||
_pitch_ref_model.update(static_cast<float>(_att_ref_sp_sub.get().timestamp - _last_update_timestamp) / 1_s,
|
||||
_last_attitude_reference_setpoint.pitch_body);
|
||||
_last_update_timestamp = _att_ref_sp_sub.get().timestamp;
|
||||
}
|
||||
|
||||
_roll_ref_model.update(static_cast<float>(math::max(now - _last_update_timestamp, static_cast<hrt_abstime>(0U))) / 1_s,
|
||||
_att_ref_sp_sub.get().roll_body);
|
||||
_pitch_ref_model.update(static_cast<float>(math::max(now - _last_update_timestamp, static_cast<hrt_abstime>(0U))) / 1_s,
|
||||
_att_ref_sp_sub.get().pitch_body);
|
||||
|
||||
}
|
||||
|
||||
_last_attitude_reference_setpoint = _att_ref_sp_sub.get();
|
||||
|
||||
_last_update_timestamp = now;
|
||||
|
||||
_attitude_setpoint_output = _att_ref_sp_sub.get();
|
||||
_attitude_setpoint_output.timestamp = now;
|
||||
|
||||
if (_param_ref_r_en.get()) {
|
||||
_attitude_setpoint_output.roll_body = _roll_ref_model.getState();
|
||||
_attitiude_rate_feedforward_output(0) = _roll_ref_model.getRate();
|
||||
_attitiude_torque_feedforward_output(0) = _roll_ref_model.getAccel();
|
||||
}
|
||||
|
||||
if (_param_ref_p_en.get()) {
|
||||
_attitude_setpoint_output.pitch_body = _pitch_ref_model.getState();
|
||||
_attitiude_rate_feedforward_output(1) = _pitch_ref_model.getRate();
|
||||
_attitiude_torque_feedforward_output(1) = _pitch_ref_model.getAccel();
|
||||
|
||||
}
|
||||
|
||||
// Other fields in the attitude setpoints are passed through
|
||||
|
||||
// Publish attitude setpoint for logging
|
||||
_att_sp_pub.publish(_attitude_setpoint_output);
|
||||
_last_att_setpoint_timestamp = _attitude_setpoint_output.timestamp;
|
||||
|
||||
} else {
|
||||
_attitude_setpoint_output = _att_sp_sub.get();
|
||||
_roll_ref_model.reset(_att_sp_sub.get().roll_body);
|
||||
_pitch_ref_model.reset(_att_sp_sub.get().pitch_body);
|
||||
_is_initialized = true;
|
||||
_last_update_timestamp = now;
|
||||
_last_att_setpoint_timestamp = _att_sp_sub.get().timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
void FixedwingAttitudeReferenceModel::reset()
|
||||
{
|
||||
_is_initialized = false;
|
||||
|
||||
if (_mode == ModelMode::MODELMODE_FILTERING) {
|
||||
_att_ref_sp_sub.update();
|
||||
_attitude_setpoint_output = _att_ref_sp_sub.get();
|
||||
|
||||
} else {
|
||||
_att_sp_sub.update();
|
||||
_attitude_setpoint_output = _att_sp_sub.get();
|
||||
}
|
||||
|
||||
_attitiude_rate_feedforward_output = matrix::Vector2f{};
|
||||
_attitiude_torque_feedforward_output = matrix::Vector2f{};
|
||||
}
|
||||
|
||||
void FixedwingAttitudeReferenceModel::parameters_update()
|
||||
{
|
||||
if (_parameter_update_sub.updated()) {
|
||||
parameter_update_s param_update;
|
||||
_parameter_update_sub.copy(¶m_update);
|
||||
|
||||
// If any parameter updated, call updateParams() to check if
|
||||
// this class attributes need updating (and do so).
|
||||
updateParams();
|
||||
|
||||
_roll_ref_model.setParameters(_param_ref_r_freq.get(), REFERENCE_MODEL_DAMPING, _param_ref_r_vel_limit.get(),
|
||||
_param_ref_r_acc_limit.get());
|
||||
_pitch_ref_model.setParameters(_param_ref_p_freq.get(), REFERENCE_MODEL_DAMPING, _param_ref_p_vel_limit.get(),
|
||||
_param_ref_p_acc_limit.get());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2023 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 <cstdint>
|
||||
#include <matrix/math.hpp>
|
||||
#include <mathlib/mathlib.h>
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
|
||||
#include <px4_platform_common/module_params.h>
|
||||
|
||||
#include <lib/mathlib/math/filter/second_order_reference_model.hpp>
|
||||
#include <lib/slew_rate/SlewRateYaw.hpp>
|
||||
|
||||
#include <uORB/Publication.hpp>
|
||||
#include <uORB/Subscription.hpp>
|
||||
#include <uORB/SubscriptionInterval.hpp>
|
||||
#include <uORB/topics/parameter_update.h>
|
||||
#include <uORB/topics/vehicle_attitude_setpoint.h>
|
||||
|
||||
using namespace time_literals;
|
||||
|
||||
class AttitudeReferenceModel : public math::SecondOrderReferenceModel<float>
|
||||
{
|
||||
public:
|
||||
AttitudeReferenceModel()
|
||||
{
|
||||
setDiscretizationMethod(math::SecondOrderReferenceModel<float>::DiscretizationMethod::kForwardEuler);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the system parameters
|
||||
*
|
||||
* Calculates the damping coefficient, spring constant, and maximum allowed
|
||||
* time step based on the natural frequency.
|
||||
*
|
||||
* @param[in] natural_freq The desired undamped natural frequency of the system [rad/s]
|
||||
* @param[in] damping_ratio The desired damping ratio of the system
|
||||
* @param[in] vel_limit the limit for the velocity [rad/s]
|
||||
* @param[in] acc_limit the limit for the acceleration [rad/s^2]
|
||||
* @param[in] jerk_limit set maximum jerk [rad/s^3]. Optional, only used in kForwardEuler mode
|
||||
* @return Whether or not the param set was successful
|
||||
*/
|
||||
bool setParameters(const float natural_freq, const float damping_ratio, float vel_limit = INFINITY,
|
||||
float acc_limit = INFINITY)
|
||||
{
|
||||
if (acc_limit < FLT_EPSILON) {
|
||||
acc_limit_ = INFINITY;
|
||||
|
||||
} else {
|
||||
acc_limit_ = acc_limit;
|
||||
}
|
||||
|
||||
if (vel_limit < FLT_EPSILON) {
|
||||
vel_limit_ = INFINITY;
|
||||
|
||||
} else {
|
||||
vel_limit_ = vel_limit;
|
||||
}
|
||||
|
||||
return math::SecondOrderReferenceModel<float>::setParameters(natural_freq, damping_ratio);
|
||||
}
|
||||
|
||||
private:
|
||||
float vel_limit_; /** velocity limit [rad/s]*/
|
||||
float acc_limit_; /** acceleration limit [rad/s^2]*/
|
||||
|
||||
/**
|
||||
* Take one integration step using Euler-forward integration
|
||||
*
|
||||
* @param[in] time_step Integration time [s]
|
||||
* @param[in] state_sample [rad]
|
||||
* @param[in] rate_sample [rad/s]
|
||||
*/
|
||||
void integrateStatesForwardEuler(const float time_step, const float &state_sample, const float &rate_sample) override
|
||||
{
|
||||
filter_accel_ = calculateInstantaneousAcceleration(state_sample, rate_sample);
|
||||
|
||||
if (filter_accel_ > 0.f) {
|
||||
filter_accel_ = math::min(math::min(filter_accel_, (vel_limit_ - filter_rate_) / time_step), acc_limit_);
|
||||
|
||||
} else {
|
||||
filter_accel_ = math::max(math::max(filter_accel_, (-vel_limit_ - filter_rate_) / time_step), -acc_limit_);
|
||||
}
|
||||
|
||||
const float new_rate = filter_rate_ + filter_accel_ * time_step;
|
||||
const float new_state = filter_state_ + filter_rate_ * time_step;
|
||||
|
||||
filter_state_ = new_state;
|
||||
filter_rate_ = new_rate;
|
||||
}
|
||||
};
|
||||
|
||||
class FixedwingAttitudeReferenceModel : public ModuleParams
|
||||
{
|
||||
public:
|
||||
FixedwingAttitudeReferenceModel();
|
||||
~FixedwingAttitudeReferenceModel() = default;
|
||||
|
||||
void update();
|
||||
|
||||
void reset();
|
||||
|
||||
const vehicle_attitude_setpoint_s &getOutput() {return _attitude_setpoint_output;};
|
||||
|
||||
const matrix::Vector2f &getRateFeedforward() {return _attitiude_rate_feedforward_output;};
|
||||
const matrix::Vector2f &getTorqueFeedforward() {return _attitiude_torque_feedforward_output;};
|
||||
|
||||
private:
|
||||
|
||||
enum class ModelMode {
|
||||
MODELMODE_THROUGHPUT,
|
||||
MODELMODE_FILTERING
|
||||
} _mode{ModelMode::MODELMODE_THROUGHPUT}; /*< Mode in which the attitude reference model works on */
|
||||
|
||||
/**
|
||||
* Check for parameter changes and update them if needed.
|
||||
*/
|
||||
void parameters_update();
|
||||
|
||||
AttitudeReferenceModel _roll_ref_model; /*< Second order reference filter for the roll angle */
|
||||
AttitudeReferenceModel _pitch_ref_model; /*< Second order reference filter for the pitch angle */
|
||||
bool _is_initialized{false}; /*< Flag indicating if the reference model is already initialized */
|
||||
uint64_t _last_att_setpoint_timestamp{UINT64_C(0)}; /*< Timestamp of the last own published vehicle attitude setpoint topic */
|
||||
hrt_abstime _last_update_timestamp{0U}; /*< Timestamp of the last update*/
|
||||
vehicle_attitude_setpoint_s _last_attitude_reference_setpoint; /*< Last attitude reference setpoint input */
|
||||
vehicle_attitude_setpoint_s _attitude_setpoint_output; /*< Attitude setpoint to be set by output*/
|
||||
matrix::Vector2f _attitiude_rate_feedforward_output; /*< Attitude rate feedforward output */
|
||||
matrix::Vector2f _attitiude_torque_feedforward_output; /*< Attitude torque feedforward output */
|
||||
|
||||
uORB::SubscriptionInterval _parameter_update_sub{ORB_ID(parameter_update), 1_s}; /*< parameter update subscription */
|
||||
uORB::SubscriptionData<vehicle_attitude_setpoint_s> _att_ref_sp_sub{ORB_ID(vehicle_attitude_reference_setpoint)}; /*< vehicle attitude reference setpoint */
|
||||
uORB::SubscriptionData<vehicle_attitude_setpoint_s> _att_sp_sub{ORB_ID(vehicle_attitude_setpoint)}; /*< vehicle attitude setpoint */
|
||||
uORB::Publication<vehicle_attitude_setpoint_s> _att_sp_pub{ORB_ID(vehicle_attitude_setpoint)}; /*< vehicle attitude setpoint publication when reference model is active for logging */
|
||||
|
||||
DEFINE_PARAMETERS(
|
||||
(ParamFloat<px4::params::FW_REF_R_FREQ>) _param_ref_r_freq,
|
||||
(ParamFloat<px4::params::FW_REF_R_V_LIM>) _param_ref_r_vel_limit,
|
||||
(ParamFloat<px4::params::FW_REF_R_A_LIM>) _param_ref_r_acc_limit,
|
||||
(ParamBool<px4::params::FW_REF_R_EN>) _param_ref_r_en,
|
||||
(ParamFloat<px4::params::FW_REF_P_FREQ>) _param_ref_p_freq,
|
||||
(ParamFloat<px4::params::FW_REF_P_V_LIM>) _param_ref_p_vel_limit,
|
||||
(ParamFloat<px4::params::FW_REF_P_A_LIM>) _param_ref_p_acc_limit,
|
||||
(ParamBool<px4::params::FW_REF_P_EN>) _param_ref_p_en
|
||||
)
|
||||
};
|
||||
@@ -254,3 +254,87 @@ PARAM_DEFINE_FLOAT(FW_MAN_R_MAX, 45.0f);
|
||||
* @group FW Attitude Control
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(FW_MAN_P_MAX, 30.0f);
|
||||
|
||||
/**
|
||||
* Natural frequency of the roll reference model
|
||||
*
|
||||
* Frequency of the critically damped second order roll reference model
|
||||
*
|
||||
* @min 0.0
|
||||
* @decimal 3
|
||||
* @group FW Attitude Control
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(FW_REF_R_FREQ, 5.0f);
|
||||
|
||||
/**
|
||||
* Velocity limit of the roll reference model
|
||||
*
|
||||
* Limit of the critically damped second order roll reference model velocity. A negative value disables the limit.
|
||||
*
|
||||
* @min -1.0
|
||||
* @decimal 3
|
||||
* @group FW Attitude Control
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(FW_REF_R_V_LIM, -1.0f);
|
||||
|
||||
/**
|
||||
* Acceleration limit of the roll reference model
|
||||
*
|
||||
* Limit of the critically damped second order roll reference model acceleration. A negative value disables the limit.
|
||||
*
|
||||
* @min -1.0
|
||||
* @decimal 3
|
||||
* @group FW Attitude Control
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(FW_REF_R_A_LIM, -1.0f);
|
||||
|
||||
/**
|
||||
* Enable roll reference model
|
||||
*
|
||||
*
|
||||
* @boolean
|
||||
* @group FW Attitude Control
|
||||
*/
|
||||
PARAM_DEFINE_INT32(FW_REF_R_EN, 0);
|
||||
|
||||
/**
|
||||
* Natural frequency of the roll reference model
|
||||
*
|
||||
* Frequency of the critically damped second order pitch reference model
|
||||
*
|
||||
* @min 0.0
|
||||
* @decimal 3
|
||||
* @group FW Attitude Control
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(FW_REF_P_FREQ, 5.0f);
|
||||
|
||||
/**
|
||||
* Velocity limit of the pitch reference model
|
||||
*
|
||||
* Limit of the critically damped second order pitch reference model velocity. A negative value disables the limit.
|
||||
*
|
||||
* @min -1.0
|
||||
* @decimal 3
|
||||
* @group FW Attitude Control
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(FW_REF_P_V_LIM, -1.0f);
|
||||
|
||||
/**
|
||||
* Acceleration limit of the pitch reference model
|
||||
*
|
||||
* Limit of the critically damped second order pitch reference model acceleration. A negative value disables the limit.
|
||||
*
|
||||
* @min -1.0
|
||||
* @decimal 3
|
||||
* @group FW Attitude Control
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(FW_REF_P_A_LIM, -1.0f);
|
||||
|
||||
/**
|
||||
* Enable pitch reference model
|
||||
*
|
||||
*
|
||||
* @boolean
|
||||
* @group FW Attitude Control
|
||||
*/
|
||||
PARAM_DEFINE_INT32(FW_REF_P_EN, 0);
|
||||
|
||||
@@ -52,6 +52,8 @@ FixedwingPositionControl::FixedwingPositionControl(bool vtol) :
|
||||
ModuleParams(nullptr),
|
||||
WorkItem(MODULE_NAME, px4::wq_configurations::nav_and_controllers),
|
||||
_attitude_sp_pub(vtol ? ORB_ID(fw_virtual_attitude_setpoint) : ORB_ID(vehicle_attitude_setpoint)),
|
||||
_attitude_ref_sp_pub(vtol ? ORB_ID(fw_virtual_vehicle_attitude_reference_setpoint) : ORB_ID(
|
||||
vehicle_attitude_reference_setpoint)),
|
||||
_loop_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": cycle")),
|
||||
_launchDetector(this),
|
||||
_runway_takeoff(this)
|
||||
@@ -2574,7 +2576,14 @@ FixedwingPositionControl::Run()
|
||||
q.copyTo(_att_sp.q_d);
|
||||
|
||||
_att_sp.timestamp = hrt_absolute_time();
|
||||
_attitude_sp_pub.publish(_att_sp);
|
||||
|
||||
// Enable reference model use for auto modes except when transitioning.
|
||||
if (_control_mode_current == FW_POSCTRL_MODE_AUTO && !_vehicle_status.in_transition_mode) {
|
||||
_attitude_ref_sp_pub.publish(_att_sp);
|
||||
|
||||
} else {
|
||||
_attitude_sp_pub.publish(_att_sp);
|
||||
}
|
||||
|
||||
// only publish status in full FW mode
|
||||
if (_vehicle_status.vehicle_type == vehicle_status_s::VEHICLE_TYPE_FIXED_WING
|
||||
|
||||
@@ -216,6 +216,7 @@ private:
|
||||
uORB::Subscription _vehicle_status_sub{ORB_ID(vehicle_status)};
|
||||
|
||||
uORB::Publication<vehicle_attitude_setpoint_s> _attitude_sp_pub;
|
||||
uORB::Publication<vehicle_attitude_setpoint_s> _attitude_ref_sp_pub;
|
||||
uORB::Publication<vehicle_local_position_setpoint_s> _local_pos_sp_pub{ORB_ID(vehicle_local_position_setpoint)};
|
||||
uORB::Publication<npfg_status_s> _npfg_status_pub{ORB_ID(npfg_status)};
|
||||
uORB::Publication<position_controller_status_s> _pos_ctrl_status_pub{ORB_ID(position_controller_status)};
|
||||
|
||||
@@ -358,6 +358,7 @@ void FixedwingRateControl::Run()
|
||||
const Vector3f angular_acceleration_setpoint = _rate_control.update(rates, body_rates_setpoint, angular_accel, dt,
|
||||
_landed);
|
||||
|
||||
const Vector3f reference_ff(_param_fw_ra_ff.get() * _rates_sp.accel_feedforward[0], _param_fw_pa_ff.get() * _rates_sp.accel_feedforward[1], 0.f);
|
||||
const Vector3f gain_ff(_param_fw_rr_ff.get(), _param_fw_pr_ff.get(), _param_fw_yr_ff.get());
|
||||
const Vector3f feedforward = gain_ff.emult(body_rates_setpoint) * _airspeed_scaling;
|
||||
|
||||
|
||||
@@ -182,6 +182,7 @@ private:
|
||||
(ParamFloat<px4::params::FW_MAN_Y_SC>) _param_fw_man_y_sc,
|
||||
|
||||
(ParamFloat<px4::params::FW_PR_FF>) _param_fw_pr_ff,
|
||||
(ParamFloat<px4::params::FW_PA_FF>) _param_fw_pa_ff,
|
||||
(ParamFloat<px4::params::FW_PR_I>) _param_fw_pr_i,
|
||||
(ParamFloat<px4::params::FW_PR_IMAX>) _param_fw_pr_imax,
|
||||
(ParamFloat<px4::params::FW_PR_P>) _param_fw_pr_p,
|
||||
@@ -189,6 +190,7 @@ private:
|
||||
|
||||
(ParamFloat<px4::params::FW_RLL_TO_YAW_FF>) _param_fw_rll_to_yaw_ff,
|
||||
(ParamFloat<px4::params::FW_RR_FF>) _param_fw_rr_ff,
|
||||
(ParamFloat<px4::params::FW_RA_FF>) _param_fw_ra_ff,
|
||||
(ParamFloat<px4::params::FW_RR_I>) _param_fw_rr_i,
|
||||
(ParamFloat<px4::params::FW_RR_IMAX>) _param_fw_rr_imax,
|
||||
(ParamFloat<px4::params::FW_RR_P>) _param_fw_rr_p,
|
||||
|
||||
@@ -211,6 +211,18 @@ PARAM_DEFINE_FLOAT(FW_YR_IMAX, 0.2f);
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(FW_RR_FF, 0.5f);
|
||||
|
||||
/**
|
||||
* roll acceleration feedforward gain
|
||||
*
|
||||
* feedforward gain for acceleration to scale rad/s^2 to percentage output
|
||||
*
|
||||
* @min 0.0
|
||||
* @max 10.0
|
||||
* @decimal 2
|
||||
* @group FW Rate Control
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(FW_RA_FF, 0.0f);
|
||||
|
||||
/**
|
||||
* Pitch rate feed forward
|
||||
*
|
||||
@@ -225,6 +237,19 @@ PARAM_DEFINE_FLOAT(FW_RR_FF, 0.5f);
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(FW_PR_FF, 0.5f);
|
||||
|
||||
/**
|
||||
* pitch acceleration feedforward gain
|
||||
*
|
||||
* feedforward gain for acceleration to scale rad/s^2 to unitless output
|
||||
*
|
||||
* @unit %/rad/s
|
||||
* @min 0.0
|
||||
* @max 10.0
|
||||
* @decimal 2
|
||||
* @group FW Rate Control
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(FW_PA_FF, 0.0f);
|
||||
|
||||
/**
|
||||
* Yaw rate feed forward
|
||||
*
|
||||
|
||||
@@ -124,6 +124,7 @@ void LoggedTopics::add_default_topics()
|
||||
add_topic("vehicle_angular_velocity", 20);
|
||||
add_topic("vehicle_attitude", 50);
|
||||
add_topic("vehicle_attitude_setpoint", 50);
|
||||
add_topic("vehicle_attitude_reference_setpoint", 50);
|
||||
add_topic("vehicle_command");
|
||||
add_topic("vehicle_command_ack");
|
||||
add_topic("vehicle_constraints", 1000);
|
||||
|
||||
@@ -44,8 +44,7 @@ add_custom_command(
|
||||
COMMAND
|
||||
${PYTHON_EXECUTABLE} ${MAVLINK_GIT_DIR}/pymavlink/tools/mavgen.py
|
||||
--lang C --wire-protocol 2.0
|
||||
#--no-validate
|
||||
#--strict-units
|
||||
--exit-code
|
||||
--output ${MAVLINK_LIBRARY_DIR}
|
||||
${MAVLINK_GIT_DIR}/message_definitions/v1.0/${MAVLINK_DIALECT_UAVIONIX}.xml > ${CMAKE_CURRENT_BINARY_DIR}/mavgen_${MAVLINK_DIALECT_UAVIONIX}.log
|
||||
DEPENDS
|
||||
@@ -64,8 +63,7 @@ add_custom_command(
|
||||
COMMAND
|
||||
${PYTHON_EXECUTABLE} ${MAVLINK_GIT_DIR}/pymavlink/tools/mavgen.py
|
||||
--lang C --wire-protocol 2.0
|
||||
#--no-validate
|
||||
#--strict-units
|
||||
--exit-code
|
||||
--output ${MAVLINK_LIBRARY_DIR}
|
||||
${MAVLINK_GIT_DIR}/message_definitions/v1.0/${CONFIG_MAVLINK_DIALECT}.xml > ${CMAKE_CURRENT_BINARY_DIR}/mavgen_${CONFIG_MAVLINK_DIALECT}.log
|
||||
DEPENDS
|
||||
|
||||
@@ -309,8 +309,7 @@ private:
|
||||
|
||||
if (_estimator_status_sub.update(&estimator_status)) {
|
||||
if (estimator_status.gps_check_fail_flags > 0 ||
|
||||
estimator_status.filter_fault_flags > 0 ||
|
||||
estimator_status.innovation_check_flags > 0) {
|
||||
estimator_status.filter_fault_flags > 0) {
|
||||
|
||||
msg->failure_flags |= HL_FAILURE_FLAG_ESTIMATOR;
|
||||
}
|
||||
|
||||
@@ -216,6 +216,23 @@ void Mission::setActiveMissionItems()
|
||||
position_setpoint_triplet_s *pos_sp_triplet = _navigator->get_position_setpoint_triplet();
|
||||
const position_setpoint_s current_setpoint_copy = pos_sp_triplet->current;
|
||||
|
||||
/* Skip VTOL/FW Takeoff item if in air, fixed-wing and didn't start the takeoff already*/
|
||||
if ((_mission_item.nav_cmd == NAV_CMD_VTOL_TAKEOFF || _mission_item.nav_cmd == NAV_CMD_TAKEOFF) &&
|
||||
(_work_item_type == WorkItemType::WORK_ITEM_TYPE_DEFAULT) &&
|
||||
(_vehicle_status_sub.get().vehicle_type == vehicle_status_s::VEHICLE_TYPE_FIXED_WING) &&
|
||||
!_land_detected_sub.get().landed) {
|
||||
if (setNextMissionItem()) {
|
||||
if (!loadCurrentMissionItem()) {
|
||||
setEndOfMissionItems();
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
setEndOfMissionItems();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (item_contains_position(_mission_item)) {
|
||||
|
||||
handleTakeoff(new_work_item_type, next_mission_items, num_found_items);
|
||||
|
||||
@@ -92,6 +92,23 @@ void RtlMissionFast::setActiveMissionItems()
|
||||
WorkItemType new_work_item_type{WorkItemType::WORK_ITEM_TYPE_DEFAULT};
|
||||
position_setpoint_triplet_s *pos_sp_triplet = _navigator->get_position_setpoint_triplet();
|
||||
|
||||
/* Skip VTOL/FW Takeoff item if in air, fixed-wing and didn't start the takeoff already*/
|
||||
if ((_mission_item.nav_cmd == NAV_CMD_VTOL_TAKEOFF || _mission_item.nav_cmd == NAV_CMD_TAKEOFF) &&
|
||||
(_work_item_type == WorkItemType::WORK_ITEM_TYPE_DEFAULT) &&
|
||||
(_vehicle_status_sub.get().vehicle_type == vehicle_status_s::VEHICLE_TYPE_FIXED_WING) &&
|
||||
!_land_detected_sub.get().landed) {
|
||||
if (setNextMissionItem()) {
|
||||
if (!loadCurrentMissionItem()) {
|
||||
setEndOfMissionItems();
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
setEndOfMissionItems();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Transition to fixed wing if necessary.
|
||||
if (_vehicle_status_sub.get().vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING &&
|
||||
_vehicle_status_sub.get().is_vtol &&
|
||||
|
||||
@@ -369,6 +369,18 @@ VtolAttitudeControl::Run()
|
||||
// check if mc and fw sp were updated
|
||||
const bool mc_att_sp_updated = _mc_virtual_att_sp_sub.update(&_mc_virtual_att_sp);
|
||||
const bool fw_att_sp_updated = _fw_virtual_att_sp_sub.update(&_fw_virtual_att_sp);
|
||||
const bool fw_att_ref_sp_updated = _fw_virtual_att_ref_sp_sub.update(&_fw_virtual_att_ref_sp);
|
||||
|
||||
if (fw_att_sp_updated) {
|
||||
_is_in_att_ref_mode = false;
|
||||
|
||||
} else if (fw_att_ref_sp_updated) {
|
||||
_is_in_att_ref_mode = true;
|
||||
}
|
||||
|
||||
if (_is_in_att_ref_mode) {
|
||||
_fw_virtual_att_sp = _fw_virtual_att_ref_sp;
|
||||
}
|
||||
|
||||
// update the vtol state machine which decides which mode we are in
|
||||
_vtol_type->update_vtol_state();
|
||||
@@ -415,6 +427,10 @@ VtolAttitudeControl::Run()
|
||||
if (fw_att_sp_updated) {
|
||||
_vtol_type->update_fw_state();
|
||||
_vehicle_attitude_sp_pub.publish(_vehicle_attitude_sp);
|
||||
|
||||
} else if (fw_att_ref_sp_updated) {
|
||||
_vtol_type->update_fw_state();
|
||||
_vehicle_attitude_ref_sp_pub.publish(_vehicle_attitude_sp);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -157,6 +157,7 @@ private:
|
||||
uORB::Subscription _action_request_sub{ORB_ID(action_request)};
|
||||
uORB::Subscription _airspeed_validated_sub{ORB_ID(airspeed_validated)};
|
||||
uORB::Subscription _fw_virtual_att_sp_sub{ORB_ID(fw_virtual_attitude_setpoint)};
|
||||
uORB::Subscription _fw_virtual_att_ref_sp_sub{ORB_ID(fw_virtual_vehicle_attitude_reference_setpoint)};
|
||||
uORB::Subscription _home_position_sub{ORB_ID(home_position)};
|
||||
uORB::Subscription _land_detected_sub{ORB_ID(vehicle_land_detected)};
|
||||
uORB::Subscription _local_pos_sp_sub{ORB_ID(vehicle_local_position_setpoint)};
|
||||
@@ -173,6 +174,7 @@ private:
|
||||
uORB::Publication<normalized_unsigned_setpoint_s> _flaps_setpoint_pub{ORB_ID(flaps_setpoint)};
|
||||
uORB::Publication<normalized_unsigned_setpoint_s> _spoilers_setpoint_pub{ORB_ID(spoilers_setpoint)};
|
||||
uORB::Publication<vehicle_attitude_setpoint_s> _vehicle_attitude_sp_pub{ORB_ID(vehicle_attitude_setpoint)};
|
||||
uORB::Publication<vehicle_attitude_setpoint_s> _vehicle_attitude_ref_sp_pub{ORB_ID(vehicle_attitude_reference_setpoint)};
|
||||
uORB::PublicationMulti<vehicle_thrust_setpoint_s> _vehicle_thrust_setpoint0_pub{ORB_ID(vehicle_thrust_setpoint)};
|
||||
uORB::PublicationMulti<vehicle_thrust_setpoint_s> _vehicle_thrust_setpoint1_pub{ORB_ID(vehicle_thrust_setpoint)};
|
||||
uORB::PublicationMulti<vehicle_torque_setpoint_s> _vehicle_torque_setpoint0_pub{ORB_ID(vehicle_torque_setpoint)};
|
||||
@@ -183,6 +185,7 @@ private:
|
||||
|
||||
vehicle_attitude_setpoint_s _vehicle_attitude_sp{}; // vehicle attitude setpoint
|
||||
vehicle_attitude_setpoint_s _fw_virtual_att_sp{}; // virtual fw attitude setpoint
|
||||
vehicle_attitude_setpoint_s _fw_virtual_att_ref_sp{}; // virtual fw attitude setpoint
|
||||
vehicle_attitude_setpoint_s _mc_virtual_att_sp{}; // virtual mc attitude setpoint
|
||||
|
||||
vehicle_torque_setpoint_s _vehicle_torque_setpoint_virtual_mc{};
|
||||
@@ -209,6 +212,8 @@ private:
|
||||
|
||||
float _air_density{atmosphere::kAirDensitySeaLevelStandardAtmos}; // [kg/m^3]
|
||||
|
||||
bool _is_in_att_ref_mode{false};
|
||||
|
||||
#if !defined(ENABLE_LOCKSTEP_SCHEDULER)
|
||||
hrt_abstime _last_run_timestamp {0};
|
||||
#endif // !ENABLE_LOCKSTEP_SCHEDULER
|
||||
|
||||
Reference in New Issue
Block a user