/**************************************************************************** * * Copyright (c) 2018 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 "FlightTaskManualPositionSmoothVel.hpp" #include #include using namespace matrix; bool FlightTaskManualPositionSmoothVel::activate() { bool ret = FlightTaskManualPosition::activate(); reset(Axes::XYZ); return ret; } void FlightTaskManualPositionSmoothVel::reActivate() { // The task is reacivated while the vehicle is on the ground. To detect takeoff in mc_pos_control_main properly // using the generated jerk, reset the z derivatives to zero reset(Axes::XYZ, true); } void FlightTaskManualPositionSmoothVel::reset(Axes axes, bool force_z_zero) { int count; switch (axes) { case Axes::XY: count = 2; break; case Axes::XYZ: count = 3; break; default: count = 0; break; } // TODO: get current accel for (int i = 0; i < count; ++i) { _smoothing[i].reset(0.f, _velocity(i), _position(i)); } // Set the z derivatives to zero if (force_z_zero) { _smoothing[2].reset(0.f, 0.f, _position(2)); } _position_lock_xy_active = false; _position_lock_z_active = false; _position_setpoint_xy_locked(0) = NAN; _position_setpoint_xy_locked(1) = NAN; _position_setpoint_z_locked = NAN; } void FlightTaskManualPositionSmoothVel::_updateSetpoints() { /* Get yaw setpont, un-smoothed position setpoints.*/ FlightTaskManualPosition::_updateSetpoints(); /* Update constraints */ _smoothing[0].setMaxAccel(MPC_ACC_HOR_MAX.get()); _smoothing[1].setMaxAccel(MPC_ACC_HOR_MAX.get()); _smoothing[0].setMaxVel(_constraints.speed_xy); _smoothing[1].setMaxVel(_constraints.speed_xy); if (_velocity_setpoint(2) < 0.f) { // up _smoothing[2].setMaxAccel(MPC_ACC_UP_MAX.get()); _smoothing[2].setMaxVel(_constraints.speed_up); } else { // down _smoothing[2].setMaxAccel(MPC_ACC_DOWN_MAX.get()); _smoothing[2].setMaxVel(_constraints.speed_down); } float jerk[3] = {_jerk_max.get(), _jerk_max.get(), _jerk_max.get()}; /* Check for position unlock * During a position lock -> position unlock transition, we have to make sure that the velocity setpoint * is continuous. We know that the output of the position loop (part of the velocity setpoint) will suddenly become null * and only the feedforward (generated by this flight task) will remain. This is why the previous input of the velocity controller * is used to set current velocity of the trajectory. */ Vector2f sticks_expo_xy = Vector2f(&_sticks_expo(0)); if (sticks_expo_xy.length() > FLT_EPSILON) { if (_position_lock_xy_active) { _smoothing[0].setCurrentVelocity(_velocity_setpoint_feedback( 0)); // Start the trajectory at the current velocity setpoint _smoothing[1].setCurrentVelocity(_velocity_setpoint_feedback(1)); _position_setpoint_xy_locked(0) = NAN; _position_setpoint_xy_locked(1) = NAN; } _position_lock_xy_active = false; } if (fabsf(_sticks_expo(2)) > FLT_EPSILON) { if (_position_lock_z_active) { _smoothing[2].setCurrentVelocity(_velocity_setpoint_feedback( 2)); // Start the trajectory at the current velocity setpoint _position_setpoint_z_locked = NAN; } _position_lock_z_active = false; } // During position lock, lower jerk to help the optimizer // to converge to 0 acceleration and velocity if (_position_lock_xy_active) { jerk[0] = 1.f; jerk[1] = 1.f; } else { jerk[0] = _jerk_max.get(); jerk[1] = _jerk_max.get(); } jerk[2] = _position_lock_z_active ? 1.f : _jerk_max.get(); for (int i = 0; i < 3; ++i) { _smoothing[i].setMaxJerk(jerk[i]); _smoothing[i].updateDurations(_deltatime, _velocity_setpoint(i)); } VelocitySmoothing::timeSynchronization(_smoothing, 2); // Synchronize x and y only if (_position_lock_xy_active) { // Check if a reset event has happened. if (_sub_vehicle_local_position->get().xy_reset_counter != _reset_counter) { // Reset the XY axes _smoothing[0].setCurrentPosition(_position(0)); _smoothing[1].setCurrentPosition(_position(1)); _reset_counter = _sub_vehicle_local_position->get().xy_reset_counter; } } if (!_position_lock_xy_active) { _smoothing[0].setCurrentPosition(_position(0)); _smoothing[1].setCurrentPosition(_position(1)); } if (!_position_lock_z_active) { _smoothing[2].setCurrentPosition(_position(2)); } Vector3f pos_sp_smooth; for (int i = 0; i < 3; ++i) { _smoothing[i].integrate(_acceleration_setpoint(i), _vel_sp_smooth(i), pos_sp_smooth(i)); _velocity_setpoint(i) = _vel_sp_smooth(i); // Feedforward _jerk_setpoint(i) = _smoothing[i].getCurrentJerk(); } // Check for position lock transition if (Vector2f(_vel_sp_smooth).length() < 0.01f && Vector2f(_acceleration_setpoint).length() < .2f && sticks_expo_xy.length() <= FLT_EPSILON) { _position_lock_xy_active = true; } if (fabsf(_vel_sp_smooth(2)) < 0.01f && fabsf(_acceleration_setpoint(2)) < .2f && fabsf(_sticks_expo(2)) <= FLT_EPSILON) { _position_lock_z_active = true; } // Set valid position setpoint while in position lock. // When the position lock condition above is false, it does not // mean that the unlock condition is true. This is why // we are checking the lock flag here. if (_position_lock_xy_active) { _position_setpoint_xy_locked(0) = pos_sp_smooth(0); _position_setpoint_xy_locked(1) = pos_sp_smooth(1); } if (_position_lock_z_active) { _position_setpoint_z_locked = pos_sp_smooth(2); } _position_setpoint(0) = _position_setpoint_xy_locked(0); _position_setpoint(1) = _position_setpoint_xy_locked(1); _position_setpoint(2) = _position_setpoint_z_locked; }