/**************************************************************************** * * 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() { reset(Axes::XY); } void FlightTaskManualPositionSmoothVel::reset(Axes axes) { 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)); } _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(MPC_Z_VEL_MAX_UP.get()); } else { // down _smoothing[2].setMaxAccel(MPC_ACC_DOWN_MAX.get()); _smoothing[2].setMaxVel(MPC_Z_VEL_MAX_DN.get()); } Vector2f vel_xy_sp = Vector2f(&_velocity_setpoint(0)); float jerk[3] = {_jerk_max.get(), _jerk_max.get(), _jerk_max.get()}; float jerk_xy = _jerk_max.get(); if (_jerk_min.get() > _jerk_max.get()) { _jerk_min.set(0.f); } if (_jerk_min.get() > FLT_EPSILON) { if (vel_xy_sp.length() < FLT_EPSILON) { // Brake jerk_xy = _jerk_max.get(); } else { jerk_xy = _jerk_min.get(); } } jerk[0] = jerk_xy; jerk[1] = jerk_xy; /* 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( 0)); // Start the trajectory at the current velocity setpoint _position_setpoint_z_locked = NAN; } _position_lock_z_active = false; } 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_setpoint_xy_locked(0) = pos_sp_smooth(0); _position_setpoint_xy_locked(1) = pos_sp_smooth(1); _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_setpoint_z_locked = pos_sp_smooth(2); _position_lock_z_active = true; } _position_setpoint(0) = _position_setpoint_xy_locked(0); _position_setpoint(1) = _position_setpoint_xy_locked(1); _position_setpoint(2) = _position_setpoint_z_locked; }