PX4 Firmware
PX4 Autopilot Software http://px4.io
FlightTaskManualAltitude.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2018 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file FlightManualAltitude.cpp
36  */
37 
39 #include <float.h>
40 #include <mathlib/mathlib.h>
41 
42 using namespace matrix;
43 
45 {
47 
48  _sub_home_position.update();
49 
50  // in addition to manual require valid position and velocity in D-direction and valid yaw
51  return ret && PX4_ISFINITE(_position(2)) && PX4_ISFINITE(_velocity(2)) && PX4_ISFINITE(_yaw);
52 }
53 
55 {
56  bool ret = FlightTaskManual::activate(last_setpoint);
57  _yaw_setpoint = NAN;
58  _yawspeed_setpoint = 0.0f;
59  _thrust_setpoint = matrix::Vector3f(0.0f, 0.0f, NAN); // altitude is controlled from position/velocity
60  _position_setpoint(2) = _position(2);
61  _velocity_setpoint(2) = 0.0f;
62  _setDefaultConstraints();
63 
64  _constraints.tilt = math::radians(_param_mpc_man_tilt_max.get());
65 
66  if (PX4_ISFINITE(_sub_vehicle_local_position.get().hagl_min)) {
67  _constraints.min_distance_to_ground = _sub_vehicle_local_position.get().hagl_min;
68 
69  } else {
70  _constraints.min_distance_to_ground = -INFINITY;
71  }
72 
73  if (PX4_ISFINITE(_sub_vehicle_local_position.get().hagl_max)) {
74  _constraints.max_distance_to_ground = _sub_vehicle_local_position.get().hagl_max;
75 
76  } else {
77  _constraints.max_distance_to_ground = INFINITY;
78  }
79 
80  _max_speed_up = _constraints.speed_up;
81  _min_speed_down = _constraints.speed_down;
82 
83  return ret;
84 }
85 
87 {
88  // Use stick input with deadzone, exponential curve and first order lpf for yawspeed
89  const float yawspeed_target = _sticks_expo(3) * math::radians(_param_mpc_man_y_max.get());
90  _yawspeed_setpoint = _applyYawspeedFilter(yawspeed_target);
91 
92  // Use sticks input with deadzone and exponential curve for vertical velocity
93  const float vel_max_z = (_sticks(2) > 0.0f) ? _constraints.speed_down : _constraints.speed_up;
94  _velocity_setpoint(2) = vel_max_z * _sticks_expo(2);
95 }
96 
98 {
99  const float den = math::max(_param_mpc_man_y_tau.get() + _deltatime, 0.001f);
100  const float alpha = _deltatime / den;
101  _yawspeed_filter_state = (1.f - alpha) * _yawspeed_filter_state + alpha * yawspeed_target;
102  return _yawspeed_filter_state;
103 }
104 
106 {
107  // Depending on stick inputs and velocity, position is locked.
108  // If not locked, altitude setpoint is set to NAN.
109 
110  // Check if user wants to break
111  const bool apply_brake = fabsf(_sticks_expo(2)) <= FLT_EPSILON;
112 
113  // Check if vehicle has stopped
114  const bool stopped = (_param_mpc_hold_max_z.get() < FLT_EPSILON || fabsf(_velocity(2)) < _param_mpc_hold_max_z.get());
115 
116  // Manage transition between use of distance to ground and distance to local origin
117  // when terrain hold behaviour has been selected.
118  if (_param_mpc_alt_mode.get() == 2) {
119  // Use horizontal speed as a transition criteria
120  float spd_xy = Vector2f(_velocity).length();
121 
122  // Use presence of horizontal stick inputs as a transition criteria
123  float stick_xy = Vector2f(&_sticks_expo(0)).length();
124  bool stick_input = stick_xy > 0.001f;
125 
126  if (_terrain_hold) {
127  bool too_fast = spd_xy > _param_mpc_hold_max_xy.get();
128 
129  if (stick_input || too_fast || !PX4_ISFINITE(_dist_to_bottom)) {
130  // Stop using distance to ground
131  _terrain_hold = false;
132  _terrain_follow = false;
133 
134  // Adjust the setpoint to maintain the same height error to reduce control transients
135  if (PX4_ISFINITE(_dist_to_ground_lock) && PX4_ISFINITE(_dist_to_bottom)) {
136  _position_setpoint(2) = _position(2) + (_dist_to_ground_lock - _dist_to_bottom);
137 
138  } else {
139  _position_setpoint(2) = _position(2);
140  }
141  }
142 
143  } else {
144  bool not_moving = spd_xy < 0.5f * _param_mpc_hold_max_xy.get();
145 
146  if (!stick_input && not_moving && PX4_ISFINITE(_dist_to_bottom)) {
147  // Start using distance to ground
148  _terrain_hold = true;
149  _terrain_follow = true;
150 
151  // Adjust the setpoint to maintain the same height error to reduce control transients
152  if (PX4_ISFINITE(_position_setpoint(2))) {
153  _dist_to_ground_lock = _dist_to_bottom + (_position_setpoint(2) - _position(2));
154  }
155  }
156  }
157 
158  }
159 
160  if ((_param_mpc_alt_mode.get() == 1 || _terrain_follow) && PX4_ISFINITE(_dist_to_bottom)) {
161  // terrain following
162  _terrainFollowing(apply_brake, stopped);
163  // respect maximum altitude
164  _respectMaxAltitude();
165 
166  } else {
167  // normal mode where height is dependent on local frame
168 
169  if (apply_brake && stopped && !PX4_ISFINITE(_position_setpoint(2))) {
170  // lock position
171  _position_setpoint(2) = _position(2);
172 
173  // Ensure that minimum altitude is respected if
174  // there is a distance sensor and distance to bottom is below minimum.
175  if (PX4_ISFINITE(_dist_to_bottom) && _dist_to_bottom < _constraints.min_distance_to_ground) {
176  _terrainFollowing(apply_brake, stopped);
177 
178  } else {
179  _dist_to_ground_lock = NAN;
180  }
181 
182  } else if (PX4_ISFINITE(_position_setpoint(2)) && apply_brake) {
183  // Position is locked but check if a reset event has happened.
184  // We will shift the setpoints.
185  if (_sub_vehicle_local_position.get().z_reset_counter != _reset_counter) {
186  _position_setpoint(2) = _position(2);
187  _reset_counter = _sub_vehicle_local_position.get().z_reset_counter;
188  }
189 
190  } else {
191  // user demands velocity change
192  _position_setpoint(2) = NAN;
193  // ensure that maximum altitude is respected
194  _respectMaxAltitude();
195  }
196  }
197 }
198 
200 {
201  const bool respectAlt = PX4_ISFINITE(_dist_to_bottom)
202  && _dist_to_bottom < _constraints.min_distance_to_ground;
203 
204  // Height above ground needs to be limited (flow / range-finder)
205  if (respectAlt) {
206  // increase altitude to minimum flow distance
207  _position_setpoint(2) = _position(2)
208  - (_constraints.min_distance_to_ground - _dist_to_bottom);
209  }
210 }
211 
212 void FlightTaskManualAltitude::_terrainFollowing(bool apply_brake, bool stopped)
213 {
214  if (apply_brake && stopped && !PX4_ISFINITE(_dist_to_ground_lock)) {
215  // User wants to break and vehicle reached zero velocity. Lock height to ground.
216 
217  // lock position
218  _position_setpoint(2) = _position(2);
219  // ensure that minimum altitude is respected
220  _respectMinAltitude();
221  // lock distance to ground but adjust first for minimum altitude
222  _dist_to_ground_lock = _dist_to_bottom - (_position_setpoint(2) - _position(2));
223 
224  } else if (apply_brake && PX4_ISFINITE(_dist_to_ground_lock)) {
225  // vehicle needs to follow terrain
226 
227  // difference between the current distance to ground and the desired distance to ground
228  const float delta_distance_to_ground = _dist_to_ground_lock - _dist_to_bottom;
229  // adjust position setpoint for the delta (note: NED frame)
230  _position_setpoint(2) = _position(2) - delta_distance_to_ground;
231 
232  } else {
233  // user demands velocity change in D-direction
234  _dist_to_ground_lock = _position_setpoint(2) = NAN;
235  }
236 }
237 
239 {
240  if (PX4_ISFINITE(_dist_to_bottom)) {
241 
242  // if there is a valid maximum distance to ground, linearly increase speed limit with distance
243  // below the maximum, preserving control loop vertical position error gain.
244  if (PX4_ISFINITE(_constraints.max_distance_to_ground)) {
245  _constraints.speed_up = math::constrain(_param_mpc_z_p.get() * (_constraints.max_distance_to_ground - _dist_to_bottom),
246  -_min_speed_down, _max_speed_up);
247 
248  } else {
249  _constraints.speed_up = _max_speed_up;
250  }
251 
252  // if distance to bottom exceeded maximum distance, slowly approach maximum distance
253  if (_dist_to_bottom > _constraints.max_distance_to_ground) {
254  // difference between current distance to ground and maximum distance to ground
255  const float delta_distance_to_max = _dist_to_bottom - _constraints.max_distance_to_ground;
256  // set position setpoint to maximum distance to ground
257  _position_setpoint(2) = _position(2) + delta_distance_to_max;
258  // limit speed downwards to 0.7m/s
259  _constraints.speed_down = math::min(_min_speed_down, 0.7f);
260 
261  } else {
262  _constraints.speed_down = _min_speed_down;
263 
264  }
265  }
266 }
267 
269 {
270  float dist_to_ground = NAN;
271 
272  // if there is a valid distance to bottom or vertical distance to home
273  if (PX4_ISFINITE(_dist_to_bottom)) {
274  dist_to_ground = _dist_to_bottom;
275 
276  } else if (_sub_home_position.get().valid_alt) {
277  dist_to_ground = -(_position(2) - _sub_home_position.get().z);
278  }
279 
280  // limit speed gradually within the altitudes MPC_LAND_ALT1 and MPC_LAND_ALT2
281  if (PX4_ISFINITE(dist_to_ground)) {
282  const float limit_down = math::gradual(dist_to_ground,
283  _param_mpc_land_alt2.get(), _param_mpc_land_alt1.get(),
284  _param_mpc_land_speed.get(), _constraints.speed_down);
285  const float limit_up = math::gradual(dist_to_ground,
286  _param_mpc_land_alt2.get(), _param_mpc_land_alt1.get(),
287  _param_mpc_tko_speed.get(), _constraints.speed_up);
288  _velocity_setpoint(2) = math::constrain(_velocity_setpoint(2), -limit_up, limit_down);
289  }
290 }
291 
293 {
294  float yaw_rotate = PX4_ISFINITE(_yaw_setpoint) ? _yaw_setpoint : _yaw;
295  Vector3f v_r = Vector3f(Dcmf(Eulerf(0.0f, 0.0f, yaw_rotate)) * Vector3f(v(0), v(1), 0.0f));
296  v(0) = v_r(0);
297  v(1) = v_r(1);
298 }
299 
301 {
302  if (_isYawInput()) {
303  _unlockYaw();
304 
305  } else {
306  _lockYaw();
307  }
308 }
309 
310 bool FlightTaskManualAltitude::_isYawInput()
311 {
312  /*
313  * A threshold larger than FLT_EPSILON is required because the
314  * _yawspeed_setpoint comes from an IIR filter and takes too much
315  * time to reach zero.
316  */
317  return fabsf(_yawspeed_setpoint) > 0.001f;
318 }
319 
321 {
322  // no fixed heading when rotating around yaw by stick
323  _yaw_setpoint = NAN;
324 }
325 
327 {
328  // hold the current heading when no more rotation commanded
329  if (!PX4_ISFINITE(_yaw_setpoint)) {
330  _yaw_setpoint = _yaw;
331  }
332 }
333 
335 {
336  // Only reset the yaw setpoint when the heading is locked
337  if (PX4_ISFINITE(_yaw_setpoint)) {
338  _yaw_setpoint += delta_psi;
339  }
340 }
341 
343 {
344  _updateHeadingSetpoints(); // get yaw setpoint
345 
346  // Thrust in xy are extracted directly from stick inputs. A magnitude of
347  // 1 means that maximum thrust along xy is demanded. A magnitude of 0 means no
348  // thrust along xy is demanded. The maximum thrust along xy depends on the thrust
349  // setpoint along z-direction, which is computed in PositionControl.cpp.
350 
351  Vector2f sp(&_sticks(0));
352  _rotateIntoHeadingFrame(sp);
353 
354  if (sp.length() > 1.0f) {
355  sp.normalize();
356  }
357 
358  _thrust_setpoint(0) = sp(0);
359  _thrust_setpoint(1) = sp(1);
360  _thrust_setpoint(2) = NAN;
361 
362  _updateAltitudeLock();
363  _respectGroundSlowdown();
364 }
365 
367 {
368  // stick is deflected above 65% throttle (_sticks(2) is in the range [-1,1])
369  return _sticks(2) < -0.3f;
370 }
371 
373 {
374  _scaleSticks();
375  _updateSetpoints();
376  _constraints.want_takeoff = _checkTakeoff();
377 
378  return true;
379 }
constexpr _Tp constrain(_Tp val, _Tp min_val, _Tp max_val)
Definition: Limits.hpp:66
bool _checkTakeoff() override
Determine when to trigger a takeoff (ignored in flight)
virtual bool activate(vehicle_local_position_setpoint_s last_setpoint)
Call once on the event where you switch to the task.
Definition: FlightTask.cpp:12
Dcm< float > Dcmf
Definition: Dcm.hpp:185
void normalize()
Definition: Vector.hpp:87
bool updateInitialize() override
Call before activate() or update() to initialize time and input data.
bool update() override
To be called regularly in the control loop cycle to execute the task.
DEFINE_PARAMETERS_CUSTOM_PARENT(FlightTaskManual,(ParamFloat< px4::params::MPC_HOLD_MAX_Z >) _param_mpc_hold_max_z,(ParamInt< px4::params::MPC_ALT_MODE >) _param_mpc_alt_mode,(ParamFloat< px4::params::MPC_HOLD_MAX_XY >) _param_mpc_hold_max_xy,(ParamFloat< px4::params::MPC_Z_P >) _param_mpc_z_p,(ParamFloat< px4::params::MPC_MAN_Y_MAX >) _param_mpc_man_y_max,(ParamFloat< px4::params::MPC_MAN_Y_TAU >) _param_mpc_man_y_tau,(ParamFloat< px4::params::MPC_MAN_TILT_MAX >) _param_mpc_man_tilt_max,(ParamFloat< px4::params::MPC_LAND_ALT1 >) _param_mpc_land_alt1,(ParamFloat< px4::params::MPC_LAND_ALT2 >) _param_mpc_land_alt2,(ParamFloat< px4::params::MPC_LAND_SPEED >) _param_mpc_land_speed,(ParamFloat< px4::params::MPC_TKO_SPEED >) _param_mpc_tko_speed) private void _unlockYaw()
#define FLT_EPSILON
void _respectMinAltitude()
Minimum Altitude during range sensor operation.
const T gradual(const T &value, const T &x_low, const T &x_high, const T &y_low, const T &y_high)
Definition: Functions.hpp:139
void _rotateIntoHeadingFrame(matrix::Vector2f &vec)
rotates vector into local frame
void _updateAltitudeLock()
Check and sets for position lock.
void _ekfResetHandlerHeading(float delta_psi) override
adjust heading setpoint in case of EKF reset event
constexpr T radians(T degrees)
Definition: Limits.hpp:85
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
Vector2< float > Vector2f
Definition: Vector2.hpp:69
void _updateHeadingSetpoints()
sets yaw or yaw speed
Euler< float > Eulerf
Definition: Euler.hpp:156
Type length() const
Definition: Vector.hpp:83
void _respectGroundSlowdown()
Sets downwards velocity constraint based on the distance to ground.
virtual void _updateSetpoints()
updates all setpoints
constexpr _Tp min(_Tp a, _Tp b)
Definition: Limits.hpp:54
float _applyYawspeedFilter(float yawspeed_target)
Filter between stick input and yaw setpoint.
bool activate(vehicle_local_position_setpoint_s last_setpoint) override
Call once on the event where you switch to the task.
bool updateInitialize() override
Call before activate() or update() to initialize time and input data.
Vector3< float > Vector3f
Definition: Vector3.hpp:136
constexpr _Tp max(_Tp a, _Tp b)
Definition: Limits.hpp:60
void _terrainFollowing(bool apply_brake, bool stopped)
Terrain following.
virtual void _scaleSticks()
scales sticks to velocity in z