aboutsummaryrefslogblamecommitdiff
path: root/src/modules/fixedwing_backside/fixedwing.cpp
blob: bbb39f20f0b195935ea96007af253676efd43050 (plain) (tree)

























































                                                                              
                                                                   
 
                                                  

















                                                                              
                                                                             
 
                                             
                                                       
                                              
                                                        
                                                

 


                                                                                                        











                                   
                                   
                              
                                

                         
                         
 




                                                                                                   
 
                             
                               
                   
                          






















                                                                          

                                                        











                                                            
                                            

                                                      
                                  
                                                                                        





                                                                       
                                 
                                                    
 


                                                                         

                                               
                                                                 
                                                                 
                                                                  


                                                                  
 
                                
                                                                                    







                                                                           
                                                                              


                                                                    

                               
                                


                                                                                             
                                                       

                                                                                     





                                                                                           
 




                                                                                
                                      
                                                        

                                                                                                      
                                                                                                   

                 
                                                             



                                                              
 

                                                                                            
 



                                                                                             
                                                                 
                                                                 
                                                                  
 




                                                                               
 


                                                                                   
 


































                                                                                                       
                 










                                                                                                                                      



















                                                                   
/****************************************************************************
 *
 *   Copyright (C) 2012 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.
 *
 ****************************************************************************/

/**
 * @file fixedwing.cpp
 *
 * Controller library code
 */

#include "fixedwing.hpp"

namespace control
{

namespace fixedwing
{

BlockYawDamper::BlockYawDamper(SuperBlock *parent, const char *name) :
	SuperBlock(parent, name),
	_rLowPass(this, "R_LP"),
	_rWashout(this, "R_HP"),
	_r2Rdr(this, "R2RDR"),
	_rudder(0)
{
}

BlockYawDamper::~BlockYawDamper() {};

void BlockYawDamper::update(float rCmd, float r, float outputScale)
{
	_rudder = outputScale*_r2Rdr.update(rCmd -
				_rWashout.update(_rLowPass.update(r)));
}

BlockStabilization::BlockStabilization(SuperBlock *parent, const char *name) :
	SuperBlock(parent, name),
	_yawDamper(this, ""),
	_pLowPass(this, "P_LP"),
	_qLowPass(this, "Q_LP"),
	_p2Ail(this, "P2AIL"),
	_q2Elv(this, "Q2ELV"),
	_aileron(0),
	_elevator(0)
{
}

BlockStabilization::~BlockStabilization() {};

void BlockStabilization::update(float pCmd, float qCmd, float rCmd,
				float p, float q, float r, float outputScale)
{
	_aileron = outputScale*_p2Ail.update(
			   pCmd - _pLowPass.update(p));
	_elevator = outputScale*_q2Elv.update(
			    qCmd - _qLowPass.update(q));
	_yawDamper.update(rCmd, r, outputScale);
}

BlockMultiModeBacksideAutopilot::BlockMultiModeBacksideAutopilot(SuperBlock *parent, const char *name) :
	BlockUorbEnabledAutopilot(parent, name),
	_stabilization(this, ""), // no name needed, already unique

	// heading hold
	_psi2Phi(this, "PSI2PHI"),
	_phi2P(this, "PHI2P"),
	_phiLimit(this, "PHI_LIM"),

	// velocity hold
	_v2Theta(this, "V2THE"),
	_theta2Q(this, "THE2Q"),
	_theLimit(this, "THE"),
	_vLimit(this, "V"),

	// altitude/climb rate hold
	_h2Thr(this, "H2THR"),
	_cr2Thr(this, "CR2THR"),

	// guidance block
	_guide(this, ""),

	_trimAil(this, "TRIM_ROLL", false), 	/* general roll trim (full name: TRIM_ROLL) */
	_trimElv(this, "TRIM_PITCH", false), 	/* general pitch trim */
	_trimRdr(this, "TRIM_YAW", false), 	/* general yaw trim */
	_trimThr(this, "TRIM_THR"), 	/* FWB_ specific throttle trim (full name: FWB_TRIM_THR) */
	_trimV(this, "TRIM_V"), 	/* FWB_ specific trim velocity (full name : FWB_TRIM_V) */

	_vCmd(this, "V_CMD"),
	_crMax(this, "CR_MAX"),
	_attPoll(),
	_lastMissionCmd(),
	_timeStamp(0)
{
	_attPoll.fd = _att.getHandle();
	_attPoll.events = POLLIN;
}

void BlockMultiModeBacksideAutopilot::update()
{
	// wait for a sensor update, check for exit condition every 100 ms
	if (poll(&_attPoll, 1, 100) < 0) return; // poll error

	uint64_t newTimeStamp = hrt_absolute_time();
	float dt = (newTimeStamp - _timeStamp) / 1.0e6f;
	_timeStamp = newTimeStamp;

	// check for sane values of dt
	// to prevent large control responses
	if (dt > 1.0f || dt < 0) return;

	// set dt for all child blocks
	setDt(dt);

	// store old position command before update if new command sent
	if (_missionCmd.updated()) {
		_lastMissionCmd = _missionCmd.getData();
	}

	// check for new updates
	if (_param_update.updated()) updateParams();

	// get new information from subscriptions
	updateSubscriptions();

	// default all output to zero unless handled by mode
	for (unsigned i = 4; i < NUM_ACTUATOR_CONTROLS; i++)
		_actuators.control[i] = 0.0f;

	// only update guidance in auto mode
	if (_status.main_state == MAIN_STATE_AUTO) {
		// TODO use vehicle_control_mode here?
		// update guidance
		_guide.update(_pos, _att, _missionCmd.current, _lastMissionCmd.current);
	}

	// XXX handle STABILIZED (loiter on spot) as well
	// once the system switches from manual or auto to stabilized
	// the setpoint should update to loitering around this position

	// handle autopilot modes
	if (_status.main_state == MAIN_STATE_AUTO) {

		// calculate velocity, XXX should be airspeed,
		// but using ground speed for now for the purpose 
		// of control we will limit the velocity feedback between
		// the min/max velocity
		float v = _vLimit.update(sqrtf(
					_pos.vel_n * _pos.vel_n +
					_pos.vel_e * _pos.vel_e +
					_pos.vel_d * _pos.vel_d));

		// limit velocity command between min/max velocity
		float vCmd = _vLimit.update(_vCmd.get());

		// altitude hold
		float dThrottle = _h2Thr.update(_missionCmd.current.alt - _pos.alt);

		// heading hold
		float psiError = _wrap_pi(_guide.getPsiCmd() - _att.yaw);
		float phiCmd = _phiLimit.update(_psi2Phi.update(psiError));
		float pCmd = _phi2P.update(phiCmd - _att.roll);

		// velocity hold
		// negative sign because nose over to increase speed
		float thetaCmd = _theLimit.update(-_v2Theta.update(vCmd - v));
		float qCmd = _theta2Q.update(thetaCmd - _att.pitch);

		// yaw rate cmd
		float rCmd = 0;

		// stabilization
		float velocityRatio = _trimV.get()/v;
		float outputScale = velocityRatio*velocityRatio;
		// this term scales the output based on the dynamic pressure change from trim
		_stabilization.update(pCmd, qCmd, rCmd,
				      _att.rollspeed, _att.pitchspeed, _att.yawspeed,
				      outputScale);

		// output
		_actuators.control[CH_AIL] = _stabilization.getAileron() + _trimAil.get();
		_actuators.control[CH_ELV] = _stabilization.getElevator() + _trimElv.get();
		_actuators.control[CH_RDR] = _stabilization.getRudder() + _trimRdr.get();
		_actuators.control[CH_THR] = dThrottle + _trimThr.get();

		// XXX limit throttle to manual setting (safety) for now.
		// If it turns out to be confusing, it can be removed later once
		// a first binary release can be targeted.
		// This is not a hack, but a design choice.

		// do not limit in HIL
		if (_status.hil_state != HIL_STATE_ON) {
			/* limit to value of manual throttle */
			_actuators.control[CH_THR] = (_actuators.control[CH_THR] < _manual.throttle) ?
						     _actuators.control[CH_THR] : _manual.throttle;
		}

	} else if (_status.main_state == MAIN_STATE_MANUAL) {
		_actuators.control[CH_AIL] = _manual.roll;
		_actuators.control[CH_ELV] = _manual.pitch;
		_actuators.control[CH_RDR] = _manual.yaw;
		_actuators.control[CH_THR] = _manual.throttle;

	} else if (_status.main_state == MAIN_STATE_ALTCTL ||
		_status.main_state == MAIN_STATE_POSCTL /* TODO, implement pos control */) {

		// calculate velocity, XXX should be airspeed, but using ground speed for now
		// for the purpose of control we will limit the velocity feedback between
		// the min/max velocity
		float v = _vLimit.update(sqrtf(
					_pos.vel_n * _pos.vel_n +
					_pos.vel_e * _pos.vel_e +
					_pos.vel_d * _pos.vel_d));

		// pitch channel -> rate of climb
		// TODO, might want to put a gain on this, otherwise commanding
		// from +1 -> -1 m/s for rate of climb
		//float dThrottle = _cr2Thr.update(
		//_crMax.get()*_manual.pitch - _pos.vz);

		// roll channel -> bank angle
		float phiCmd = _phiLimit.update(_manual.roll * _phiLimit.getMax());
		float pCmd = _phi2P.update(phiCmd - _att.roll);

		// throttle channel -> velocity
		// negative sign because nose over to increase speed
		float vCmd = _vLimit.update(_manual.throttle *
				(_vLimit.getMax() - _vLimit.getMin()) +
				_vLimit.getMin());
		float thetaCmd = _theLimit.update(-_v2Theta.update(vCmd - v));
		float qCmd = _theta2Q.update(thetaCmd - _att.pitch);

		// yaw rate cmd
		float rCmd = 0;

		// stabilization
		_stabilization.update(pCmd, qCmd, rCmd,
					  _att.rollspeed, _att.pitchspeed, _att.yawspeed);

		// output
		_actuators.control[CH_AIL] = _stabilization.getAileron() + _trimAil.get();
		_actuators.control[CH_ELV] = _stabilization.getElevator() + _trimElv.get();
		_actuators.control[CH_RDR] = _stabilization.getRudder() + _trimRdr.get();

		// currently using manual throttle
		// XXX if you enable this watch out, vz might be very noisy
		//_actuators.control[CH_THR] = dThrottle + _trimThr.get();
		_actuators.control[CH_THR] = _manual.throttle;

		// XXX limit throttle to manual setting (safety) for now.
		// If it turns out to be confusing, it can be removed later once
		// a first binary release can be targeted.
		// This is not a hack, but a design choice.

		/* do not limit in HIL */
		if (_status.hil_state != HIL_STATE_ON) {
			/* limit to value of manual throttle */
			_actuators.control[CH_THR] = (_actuators.control[CH_THR] < _manual.throttle) ?
							 _actuators.control[CH_THR] : _manual.throttle;
		}
	// body rates controller, disabled for now
	// TODO
	} else if (0 /*_status.manual_control_mode == VEHICLE_MANUAL_CONTROL_MODE_SAS*/) {	// TODO use vehicle_control_mode here?

		_stabilization.update(_manual.roll, _manual.pitch, _manual.yaw,
					  _att.rollspeed, _att.pitchspeed, _att.yawspeed);

		_actuators.control[CH_AIL] = _stabilization.getAileron();
		_actuators.control[CH_ELV] = _stabilization.getElevator();
		_actuators.control[CH_RDR] = _stabilization.getRudder();
		_actuators.control[CH_THR] = _manual.throttle;
	}

	// update all publications
	updatePublications();
}

BlockMultiModeBacksideAutopilot::~BlockMultiModeBacksideAutopilot()
{
	// send one last publication when destroyed, setting
	// all output to zero
	for (unsigned i = 0; i < NUM_ACTUATOR_CONTROLS; i++)
		_actuators.control[i] = 0.0f;

	updatePublications();
}

} // namespace fixedwing

} // namespace control