Skip to content

Commit 0c8a759

Browse files
committed
land_detector: multicopter ground contact robustness, fixes, and cleanup
- if "landed" and "maybe_landed" states are false then both the "hit_ground" and the "low_thrust" condition need to be true in order to detect landing - ground contact MC NAN setpoint workaround - ground contact additionally check acceleration setpoint - schedule with vehicle_local_position updates (most updates require valid local position) - don't allow LNDMC_Z_VEL_MAX to exceed MPC_LAND_SPEED - ground contact horizontal and vertical movement checks default to failed if estimates aren't available
1 parent ca33bb1 commit 0c8a759

13 files changed

+225
-315
lines changed

src/modules/commander/Commander.cpp

-7
Original file line numberDiff line numberDiff line change
@@ -1575,7 +1575,6 @@ Commander::run()
15751575
/* Update land detector */
15761576
if (_land_detector_sub.updated()) {
15771577
_was_landed = _land_detector.landed;
1578-
bool was_falling = _land_detector.freefall;
15791578
_land_detector_sub.copy(&_land_detector);
15801579

15811580
// Only take actions if armed
@@ -1596,12 +1595,6 @@ Commander::run()
15961595
_lvel_probation_time_us = _param_com_pos_fs_prob.get() * 1_s;
15971596
}
15981597
}
1599-
1600-
if (was_falling != _land_detector.freefall) {
1601-
if (_land_detector.freefall) {
1602-
mavlink_log_info(&mavlink_log_pub, "Freefall detected");
1603-
}
1604-
}
16051598
}
16061599
}
16071600

src/modules/land_detector/FixedwingLandDetector.cpp

+7-12
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,10 @@ FixedwingLandDetector::FixedwingLandDetector()
5151
_landed_hysteresis.set_hysteresis_time_from(true, FLYING_TRIGGER_TIME_US);
5252
}
5353

54-
void FixedwingLandDetector::_update_topics()
55-
{
56-
LandDetector::_update_topics();
57-
_airspeed_validated_sub.update(&_airspeed_validated);
58-
}
59-
6054
bool FixedwingLandDetector::_get_landed_state()
6155
{
6256
// Only trigger flight conditions if we are armed.
63-
if (!_actuator_armed.armed) {
57+
if (!_armed) {
6458
return true;
6559
}
6660

@@ -83,19 +77,20 @@ bool FixedwingLandDetector::_get_landed_state()
8377
_velocity_z_filtered = val;
8478
}
8579

80+
airspeed_validated_s airspeed_validated{};
81+
_airspeed_validated_sub.copy(&airspeed_validated);
82+
8683
// set _airspeed_filtered to 0 if airspeed data is invalid
87-
if (!PX4_ISFINITE(_airspeed_validated.true_airspeed_m_s) || hrt_elapsed_time(&_airspeed_validated.timestamp) > 1_s) {
84+
if (!PX4_ISFINITE(airspeed_validated.true_airspeed_m_s) || hrt_elapsed_time(&airspeed_validated.timestamp) > 1_s) {
8885
_airspeed_filtered = 0.0f;
8986

9087
} else {
91-
_airspeed_filtered = 0.95f * _airspeed_filtered + 0.05f * _airspeed_validated.true_airspeed_m_s;
88+
_airspeed_filtered = 0.95f * _airspeed_filtered + 0.05f * airspeed_validated.true_airspeed_m_s;
9289
}
9390

9491
// A leaking lowpass prevents biases from building up, but
9592
// gives a mostly correct response for short impulses.
96-
const matrix::Vector3f accel{_vehicle_acceleration.xyz};
97-
const float acc_hor = sqrtf(accel(0) * accel(0) + accel(1) * accel(1));
98-
93+
const float acc_hor = sqrtf(_acceleration(0) * _acceleration(0) + _acceleration(1) * _acceleration(1));
9994
_xy_accel_filtered = _xy_accel_filtered * 0.8f + acc_hor * 0.18f;
10095

10196
// Crude land detector for fixedwing.

src/modules/land_detector/FixedwingLandDetector.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class FixedwingLandDetector final : public LandDetector
6161
protected:
6262

6363
bool _get_landed_state() override;
64-
void _update_topics() override;
64+
void _update_topics() override {};
6565

6666
private:
6767

@@ -71,8 +71,6 @@ class FixedwingLandDetector final : public LandDetector
7171

7272
uORB::Subscription _airspeed_validated_sub{ORB_ID(airspeed_validated)};
7373

74-
airspeed_validated_s _airspeed_validated{};
75-
7674
float _airspeed_filtered{0.0f};
7775
float _velocity_xy_filtered{0.0f};
7876
float _velocity_z_filtered{0.0f};

src/modules/land_detector/LandDetector.cpp

+41-45
Original file line numberDiff line numberDiff line change
@@ -57,21 +57,52 @@ LandDetector::~LandDetector()
5757

5858
void LandDetector::start()
5959
{
60-
_update_params();
61-
ScheduleOnInterval(LAND_DETECTOR_UPDATE_INTERVAL);
60+
ScheduleDelayed(50_ms);
61+
_vehicle_local_position_sub.registerCallback();
6262
}
6363

6464
void LandDetector::Run()
6565
{
66+
// push backup schedule
67+
ScheduleDelayed(50_ms);
68+
6669
perf_begin(_cycle_perf);
6770

68-
if (_parameter_update_sub.updated()) {
71+
if (_parameter_update_sub.updated() || (_land_detected.timestamp == 0)) {
72+
parameter_update_s param_update;
73+
_parameter_update_sub.copy(&param_update);
74+
75+
updateParams();
6976
_update_params();
77+
78+
_total_flight_time = static_cast<uint64_t>(_param_total_flight_time_high.get()) << 32;
79+
_total_flight_time |= static_cast<uint32_t>(_param_total_flight_time_low.get());
80+
}
81+
82+
actuator_armed_s actuator_armed;
83+
84+
if (_actuator_armed_sub.update(&actuator_armed)) {
85+
_armed = actuator_armed.armed;
7086
}
7187

72-
_actuator_armed_sub.update(&_actuator_armed);
88+
vehicle_acceleration_s vehicle_acceleration;
89+
90+
if (_vehicle_acceleration_sub.update(&vehicle_acceleration)) {
91+
_acceleration = matrix::Vector3f{vehicle_acceleration.xyz};
92+
}
93+
94+
_vehicle_local_position_sub.update(&_vehicle_local_position);
95+
_vehicle_status_sub.update(&_vehicle_status);
96+
7397
_update_topics();
74-
_update_state();
98+
99+
const hrt_abstime now_us = hrt_absolute_time();
100+
101+
_freefall_hysteresis.set_state_and_update(_get_freefall_state(), now_us);
102+
_ground_contact_hysteresis.set_state_and_update(_get_ground_contact_state(), now_us);
103+
_maybe_landed_hysteresis.set_state_and_update(_get_maybe_landed_state(), now_us);
104+
_landed_hysteresis.set_state_and_update(_get_landed_state(), now_us);
105+
_ground_effect_hysteresis.set_state_and_update(_get_ground_effect_state(), now_us);
75106

76107
const bool freefallDetected = _freefall_hysteresis.get_state();
77108
const bool ground_contactDetected = _ground_contact_hysteresis.get_state();
@@ -80,8 +111,6 @@ void LandDetector::Run()
80111
const float alt_max = _get_max_altitude() > 0.0f ? _get_max_altitude() : INFINITY;
81112
const bool in_ground_effect = _ground_effect_hysteresis.get_state();
82113

83-
const hrt_abstime now = hrt_absolute_time();
84-
85114
// publish at 1 Hz, very first time, or when the result has changed
86115
if ((hrt_elapsed_time(&_land_detected.timestamp) >= 1_s) ||
87116
(_land_detected.landed != landDetected) ||
@@ -93,24 +122,23 @@ void LandDetector::Run()
93122

94123
if (!landDetected && _land_detected.landed && _takeoff_time == 0) { /* only set take off time once, until disarming */
95124
// We did take off
96-
_takeoff_time = now;
125+
_takeoff_time = now_us;
97126
}
98127

99-
_land_detected.timestamp = hrt_absolute_time();
100128
_land_detected.landed = landDetected;
101129
_land_detected.freefall = freefallDetected;
102130
_land_detected.maybe_landed = maybe_landedDetected;
103131
_land_detected.ground_contact = ground_contactDetected;
104132
_land_detected.alt_max = alt_max;
105133
_land_detected.in_ground_effect = in_ground_effect;
106-
134+
_land_detected.timestamp = hrt_absolute_time();
107135
_vehicle_land_detected_pub.publish(_land_detected);
108136
}
109137

110138
// set the flight time when disarming (not necessarily when landed, because all param changes should
111139
// happen on the same event and it's better to set/save params while not in armed state)
112-
if (_takeoff_time != 0 && !_actuator_armed.armed && _previous_armed_state) {
113-
_total_flight_time += now - _takeoff_time;
140+
if (_takeoff_time != 0 && !_armed && _previous_armed_state) {
141+
_total_flight_time += now_us - _takeoff_time;
114142
_takeoff_time = 0;
115143

116144
uint32_t flight_time = (_total_flight_time >> 32) & 0xffffffff;
@@ -124,7 +152,7 @@ void LandDetector::Run()
124152
_param_total_flight_time_low.commit_no_notification();
125153
}
126154

127-
_previous_armed_state = _actuator_armed.armed;
155+
_previous_armed_state = _armed;
128156

129157
perf_end(_cycle_perf);
130158

@@ -134,36 +162,4 @@ void LandDetector::Run()
134162
}
135163
}
136164

137-
void LandDetector::_update_params()
138-
{
139-
parameter_update_s param_update;
140-
_parameter_update_sub.copy(&param_update);
141-
142-
updateParams();
143-
_update_total_flight_time();
144-
}
145-
146-
void LandDetector::_update_state()
147-
{
148-
const hrt_abstime now_us = hrt_absolute_time();
149-
_freefall_hysteresis.set_state_and_update(_get_freefall_state(), now_us);
150-
_ground_contact_hysteresis.set_state_and_update(_get_ground_contact_state(), now_us);
151-
_maybe_landed_hysteresis.set_state_and_update(_get_maybe_landed_state(), now_us);
152-
_landed_hysteresis.set_state_and_update(_get_landed_state(), now_us);
153-
_ground_effect_hysteresis.set_state_and_update(_get_ground_effect_state(), now_us);
154-
}
155-
156-
void LandDetector::_update_topics()
157-
{
158-
_actuator_armed_sub.update(&_actuator_armed);
159-
_vehicle_acceleration_sub.update(&_vehicle_acceleration);
160-
_vehicle_local_position_sub.update(&_vehicle_local_position);
161-
}
162-
163-
void LandDetector::_update_total_flight_time()
164-
{
165-
_total_flight_time = static_cast<uint64_t>(_param_total_flight_time_high.get()) << 32;
166-
_total_flight_time |= static_cast<uint32_t>(_param_total_flight_time_low.get());
167-
}
168-
169165
} // namespace land_detector

src/modules/land_detector/LandDetector.h

+20-25
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,13 @@
5656
#include <px4_platform_common/px4_work_queue/ScheduledWorkItem.hpp>
5757
#include <uORB/Publication.hpp>
5858
#include <uORB/Subscription.hpp>
59+
#include <uORB/SubscriptionCallback.hpp>
5960
#include <uORB/topics/actuator_armed.h>
6061
#include <uORB/topics/parameter_update.h>
6162
#include <uORB/topics/vehicle_acceleration.h>
6263
#include <uORB/topics/vehicle_land_detected.h>
6364
#include <uORB/topics/vehicle_local_position.h>
65+
#include <uORB/topics/vehicle_status.h>
6466

6567
using namespace time_literals;
6668

@@ -70,11 +72,9 @@ namespace land_detector
7072
class LandDetector : public ModuleBase<LandDetector>, ModuleParams, px4::ScheduledWorkItem
7173
{
7274
public:
73-
7475
LandDetector();
7576
virtual ~LandDetector();
7677

77-
7878
/** @see ModuleBase */
7979
static int custom_command(int argc, char *argv[])
8080
{
@@ -99,12 +99,12 @@ class LandDetector : public ModuleBase<LandDetector>, ModuleParams, px4::Schedul
9999
/**
100100
* Updates parameters.
101101
*/
102-
virtual void _update_params();
102+
virtual void _update_params() {};
103103

104104
/**
105105
* Updates subscribed uORB topics.
106106
*/
107-
virtual void _update_topics();
107+
virtual void _update_topics() = 0;
108108

109109
/**
110110
* @return true if UAV is in a landed state.
@@ -136,17 +136,22 @@ class LandDetector : public ModuleBase<LandDetector>, ModuleParams, px4::Schedul
136136
*/
137137
virtual bool _get_ground_effect_state() { return false; }
138138

139-
/** Run main land detector loop at this interval. */
140-
static constexpr uint32_t LAND_DETECTOR_UPDATE_INTERVAL = 20_ms;
141-
142139
systemlib::Hysteresis _freefall_hysteresis{false};
143140
systemlib::Hysteresis _landed_hysteresis{true};
144141
systemlib::Hysteresis _maybe_landed_hysteresis{true};
145142
systemlib::Hysteresis _ground_contact_hysteresis{true};
146143
systemlib::Hysteresis _ground_effect_hysteresis{false};
147144

148-
actuator_armed_s _actuator_armed{};
149-
vehicle_acceleration_s _vehicle_acceleration{};
145+
vehicle_local_position_s _vehicle_local_position{};
146+
vehicle_status_s _vehicle_status{};
147+
148+
matrix::Vector3f _acceleration{};
149+
150+
bool _armed{false};
151+
bool _previous_armed_state{false}; ///< stores the previous actuator_armed.armed state
152+
153+
private:
154+
void Run() override;
150155

151156
vehicle_land_detected_s _land_detected = {
152157
.timestamp = 0,
@@ -157,29 +162,19 @@ class LandDetector : public ModuleBase<LandDetector>, ModuleParams, px4::Schedul
157162
.landed = true,
158163
};
159164

160-
vehicle_local_position_s _vehicle_local_position{};
161-
162-
uORB::Publication<vehicle_land_detected_s> _vehicle_land_detected_pub{ORB_ID(vehicle_land_detected)};
163-
164-
private:
165-
166-
void Run() override;
167-
168-
void _update_state();
169-
170-
void _update_total_flight_time();
171-
172-
bool _previous_armed_state{false}; ///< stores the previous actuator_armed.armed state
173-
174165
hrt_abstime _takeoff_time{0};
175166
hrt_abstime _total_flight_time{0}; ///< total vehicle flight time in microseconds
176167

177-
perf_counter_t _cycle_perf{perf_alloc(PC_ELAPSED, "land_detector_cycle")};
168+
perf_counter_t _cycle_perf{perf_alloc(PC_ELAPSED, MODULE_NAME": cycle")};
169+
170+
uORB::Publication<vehicle_land_detected_s> _vehicle_land_detected_pub{ORB_ID(vehicle_land_detected)};
178171

179172
uORB::Subscription _actuator_armed_sub{ORB_ID(actuator_armed)};
180173
uORB::Subscription _parameter_update_sub{ORB_ID(parameter_update)};
181174
uORB::Subscription _vehicle_acceleration_sub{ORB_ID(vehicle_acceleration)};
182-
uORB::Subscription _vehicle_local_position_sub{ORB_ID(vehicle_local_position)};
175+
uORB::Subscription _vehicle_status_sub{ORB_ID(vehicle_status)};
176+
177+
uORB::SubscriptionCallbackWorkItem _vehicle_local_position_sub{this, ORB_ID(vehicle_local_position)};
183178

184179
DEFINE_PARAMETERS_CUSTOM_PARENT(
185180
ModuleParams,

0 commit comments

Comments
 (0)