Skip to content

[control allocator] Enhance Tailsitter control allocation to support more complex drone configurations#26320

Open
mengchaoheng wants to merge 1 commit intoPX4:mainfrom
mengchaoheng:pr_tailsitter_effectiveness
Open

[control allocator] Enhance Tailsitter control allocation to support more complex drone configurations#26320
mengchaoheng wants to merge 1 commit intoPX4:mainfrom
mengchaoheng:pr_tailsitter_effectiveness

Conversation

@mengchaoheng
Copy link
Copy Markdown
Contributor

@mengchaoheng mengchaoheng commented Jan 21, 2026

Features

  • In hover mode, change the tailsitter's angular velocity control from the FW controller to the MC controller,

  • Add a parameter to disable a specified control surface, and support switching the control effect matrix during flight mode transitions.

Solved Problem

Fixes #25404

Solution

In the original code logic, all control surfaces are used in fixed-wing mode or during the transition phase, while control surfaces are not used in hover mode (unless the parameter VT_ELEV_MC_LOCK = 0), and the control torque comes from the FW controller.

Now, the MC controller is used when VT_ELEV_MC_LOCK = 0 in hover mode, and a new parameter VT_TS_CS_HVR_DIS is added to disable specific control surfaces, such as disabling control surfaces that are not affected by the propeller wash. The other modes (fixed-wing mode or transition phase) remain unchanged.

I disable some control surfaces by setting certain columns of the control effect matrix to 0, rather than masking to set the actuator output to 0 (by ActuatorEffectivenessTailsitterVTOL::updateSetpoint). The logic behind this is that if the control effect matrix contains columns corresponding to disabled control surfaces, the pseudo-inverse method for solving the control allocation problem will introduce coupling. This is proven by the calculation results of a simple example in Matlab:

clc;
clear all;
% Control effect model: B * u = v, for the desired torque v, 
% the pseudo-inverse allocation method uses u = B^{+} * v 
% to solve the actuator command u.
v=[1;0;0];
% Control effect matrix when using all control surfaces
B1=[0 0 0.4;0.5 0.5 0.1;-0.5 0.5 0.1]
% If the third control surface has no propeller slipstream, i.e., it has failed
B2=[0 0 0;0.5 0.5 0;-0.5 0.5 0]
% Pseudo-inverse of the effect matrix
B1_inv=pinv(B1)
B2_inv=pinv(B2)

% Comparison of two methods for disabling failed actuators:
% 1. By setting the actuator command to zero
u1=B1_inv*v;
u1(3)=0; % If setting the actuator command to zero by updateSetpoint
u1
% 2. Solved actuator commands by setting the corresponding columns of the control effect matrix to zero
u2=B2_inv*v

% Results:
% u1 =[0;-0.5;0]. Clearly, there is coupling; 
% the presence of failed control surfaces causes the desired roll torque to produce outputs on other control surfaces, 
% even though these surfaces do not have the ability to generate roll torque.
% In contrast
% u2 =[0; 0; 0]

@mengchaoheng mengchaoheng changed the title Enhance Tailsitter control allocation to support more complex drone configurations [control allocator] Enhance Tailsitter control allocation to support more complex drone configurations Jan 21, 2026
@farhangnaderi farhangnaderi force-pushed the pr_tailsitter_effectiveness branch from 64ecee2 to 2024ea1 Compare January 22, 2026 05:29
@mengchaoheng mengchaoheng force-pushed the pr_tailsitter_effectiveness branch from 2024ea1 to 5b86eb2 Compare January 22, 2026 08:42
@mengchaoheng
Copy link
Copy Markdown
Contributor Author

Could you please help me find a reviewer? @farhangnaderi

@mengchaoheng mengchaoheng force-pushed the pr_tailsitter_effectiveness branch 2 times, most recently from 8009edc to 028bf97 Compare January 26, 2026 12:17
@farhangnaderi farhangnaderi force-pushed the pr_tailsitter_effectiveness branch from 028bf97 to f55e314 Compare January 26, 2026 20:49
@mengchaoheng mengchaoheng force-pushed the pr_tailsitter_effectiveness branch 2 times, most recently from 8594814 to fd252be Compare February 3, 2026 13:36
@farhangnaderi
Copy link
Copy Markdown
Contributor

@mengchaoheng How can I test this?

@farhangnaderi farhangnaderi self-requested a review February 3, 2026 15:01
… hover,

add parameter to disable specified control surfaces,
and update control effectiveness matrix during flight mode transitions
@mengchaoheng mengchaoheng force-pushed the pr_tailsitter_effectiveness branch from fd252be to d5db2d9 Compare February 4, 2026 04:05
Copilot AI review requested due to automatic review settings February 4, 2026 04:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request enhances tailsitter control allocation to support more complex drone configurations, specifically addressing the need to use different control effectiveness matrices for different flight modes and to selectively disable control surfaces in hover mode.

Changes:

  • Switches tailsitter angular velocity control in hover mode from the fixed-wing (FW) controller to the multicopter (MC) controller when VT_ELEV_MC_LOCK=0
  • Adds a new parameter VT_TS_CS_HVR_DIS to selectively disable specific control surfaces in hover mode (e.g., surfaces outside propeller slipstream)
  • Implements dynamic control effectiveness matrix updates based on flight phase transitions

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
src/modules/vtol_att_control/vtol_att_control_params.c Defines new bitmask parameter VT_TS_CS_HVR_DIS to disable specific control surfaces in hover mode
src/modules/vtol_att_control/tailsitter.cpp Modifies control surface torque assignment logic to use MC controller in hover when surfaces are unlocked
src/modules/control_allocator/VehicleActuatorEffectiveness/ActuatorEffectivenessTailsitterVTOL.hpp Adds parameter handles, cached parameter values, and update flag for dynamic matrix updates
src/modules/control_allocator/VehicleActuatorEffectiveness/ActuatorEffectivenessTailsitterVTOL.cpp Implements parameter handling, effectiveness matrix modification based on flight phase, and matrix update triggering
Comments suppressed due to low confidence (1)

src/modules/vtol_att_control/tailsitter.cpp:341

  • The logic change here introduces a behavior change for the case when VT_ELEV_MC_LOCK=1 (locked) and the vehicle is in MC_MODE (hover).

Original behavior: When VT_ELEV_MC_LOCK=1 in MC_MODE, the condition (!_param_vt_elev_mc_lock.get() || _vtol_mode != vtol_mode::MC_MODE) evaluated to FALSE, so torque_setpoint_1 remained at zero (initialized at line 271-273), effectively locking the control surfaces.

New behavior: When VT_ELEV_MC_LOCK=1 in MC_MODE, the condition (!_param_vt_elev_mc_lock.get() && _vtol_mode == vtol_mode::MC_MODE) evaluates to FALSE, so the else branch executes and assigns FW torque to the control surfaces.

This means control surfaces are now driven by the FW controller output even in hover mode when they should be locked. This contradicts the VT_ELEV_MC_LOCK parameter documentation which states "If set to 1 the control surfaces are locked at the disarmed value in multicopter mode."

The correct logic should explicitly handle the locked case in MC_MODE by setting torque to zero or not updating it from the initialized zero value.

	if (!_param_vt_elev_mc_lock.get() && _vtol_mode == vtol_mode::MC_MODE) {
		// In MC_MODE apply torque from multirotor controller
		_torque_setpoint_1->xyz[0] = _vehicle_torque_setpoint_virtual_mc->xyz[0];
		_torque_setpoint_1->xyz[1] = _vehicle_torque_setpoint_virtual_mc->xyz[1];
		_torque_setpoint_1->xyz[2] = _vehicle_torque_setpoint_virtual_mc->xyz[2];

	} else {
		_torque_setpoint_1->xyz[0] = _vehicle_torque_setpoint_virtual_fw->xyz[0];
		_torque_setpoint_1->xyz[1] = _vehicle_torque_setpoint_virtual_fw->xyz[1];
		_torque_setpoint_1->xyz[2] = _vehicle_torque_setpoint_virtual_fw->xyz[2];
	}

@mengchaoheng
Copy link
Copy Markdown
Contributor Author

mengchaoheng commented Feb 4, 2026

How can I test this?

I can briefly summarize this PR:

  1. The main changes in tailsitter.cpp are intended to use the MC controller when _vtol_mode == MC_MODE, which can be verified by adjusting the PID parameters of the MC controller during hover and observing if it works.

  2. The main modification in ActuatorEffectivenessTailsitterVTOL.cpp is the use of the newly added parameter VT_TS_CS_HVR_DIS to update the control effectiveness matrix Effectiveness when necessary. The logic for updating Effectiveness is referenced from ActuatorEffectivenessTiltrotorVTOL.cpp.

There are two methods to check the actual effect:

  1. The simulation of the 1041_gazebo-classic_tailsitter airframe can be used for verification. After running make px4_sitl gazebo-classic_tailsitter to start the simulation, set the parameter VT_ELEV_MC_LOCK=0, then run control_allocator status in the terminal. At this point, both control surfaces are enabled (VT_TS_CS_HVR_DIS =0). Then set VT_TS_CS_HVR_DIS =1 and run control_allocator status again to observe the changes in the control effect matrix. The expected result is that the torque values corresponding to the first control surface will all be zero. Of course, this simulation is not yet using the control surfaces for control, which will be changed in another PR. Here is the effect:

When VT_TS_CS_HVR_DIS = 0:

pxh> control_allocator status
...
INFO  [control_allocator] Instance: 1
INFO  [control_allocator]   Effectiveness =
  | 0      | 1      
Mx| 0        0       
My| 0.50000  0.50000 
Mz|-0.50000  0.50000 
Fx| 0        0       
Fy| 0        0       
Fz| 0        0       
...

When VT_TS_CS_HVR_DIS = 1, we can see that the control effect (moment) of the first control surface (first column) is set to 0:

pxh> control_allocator status
...
INFO  [control_allocator] Instance: 1
INFO  [control_allocator]   Effectiveness =
  | 0      | 1      
Mx| 0        0       
My| 0        0.50000 
Mz| 0        0.50000 
Fx| 0        0       
Fy| 0        0       
Fz| 0        0    
...
  1. You can also test this using the SHW09_VTOL model from our open-source DFUAV project by running the command
make px4_sitl gazebo-classic_SHW09_vtol

This model has been extensively validated, with real-world flight videos available on YouTube, and a SITL simulation video demonstrating the specific tests related to this PR is also available for review.

@hamishwillee
Copy link
Copy Markdown
Contributor

FWIW tailsitter seems to be getting some interest at the moment - #26394

@mengchaoheng
Copy link
Copy Markdown
Contributor Author

mengchaoheng commented Feb 5, 2026

FWIW tailsitter seems to be getting some interest at the moment - #26394

This entirely depends on the reviewers. My opinion is that the tailsitter is an existing aircraft type and doesn't need to be added as a new model. Only some details need to be refined, and so far my pull request seems to be working well. Of course, whether this work is meaningful depends entirely on the reviewers. If another pull request can solve my needs, I would be happy to use their method.

Update: I have confirmed that another PR(#26394) is related to the effect of the rotor in the control effect matrix. However, this PR is related to the control surface.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

How to migrate my DFUAV project to v.1.15.4 by config control allocator.

4 participants