VTOL Pusher Assist Algorithm Improvement

Dear Developers,

@LorenzMeier, @rroche, @bresch, @JulianOes

The current forward propulsion assist algorithm (vtol_type.cpp -> pusher_assist) to overcome the drag due to wind works when VT_DWN_PITCH_MAX is reached. However there are some drawbacks of this ON/OFF controller:

  • When the forward propulsion is engaged, descend/climb pauses in landing/takeoff modes. It drammatically increases battery drainage for heavy platforms
  • Not having a PID controller, especially integrator, does not allow to trim the forward throttle around a value which corresponds Thrust = Drag.

Of course some fault scenarios must be covered in a better way as well. Detecting pusher engine thrust loss based on horizontal position error over a timeout, and then allowing an “emergency/secondary down pitch limit” might be a solution.

Secondarily, if a truncated landing cone on top of the takeoff/landing point is created with user-adjustable top and bottom radius, then climb/descend may be paused ONLY when outside this cone rather than always.



@sfuhrer Is that expected?

There is a PID controller in the velocity loop. Then, the pusher thrust scale needs to be adjusted to have the same thrust as the drone pitching down. If that doesn’t work on you vehicle, it means that the scale isn’t set correctly. There is also often a dead-zone in the pwm command; if you set the min PWM such that the motor immediately start to spin when forward thrust is commanded, you can achieve really tight velocity tracking.

Yes, this is something absolutely required, I think it should already planned to implement a pusher loss detection but I’m not sure when. @sfuhrer Could you comment on that?

@bresch thank you for your reply!

Here there is an example from a flight test:

When pusher engaged during vertical climb:

Altitude command is held until pusher is disengaged:

And I saw that this happenes multiple times in windy days.

I use VT_FWD_THRUST_SC = 2. As far as I checked the source core, VtolType::pusher_assist() calculates the forward_thrust based on current pitch_down, VT_DWN_PITCH_MAX, and VT_FWD_THRUST_SC. I couldn’t see a velocity based PID control during pusher assist. May you refer where it is done please?

forward_thrust = (sinf(-pitch_down) - sinf(_params->down_pitch_max)) * _params->forward_thrust_scale;
	// limit forward actuation to [0, 0.9]
	forward_thrust = math::constrain(forward_thrust, 0.0f, 0.9f);

@ozanyuceol I think I understood what’s happening: the horizontal position error grows and since the pitch is not enough to compensate, the pusher starts. At the same time, also because the XY position error is large, the trajectory is paused (this is a safety logic: the trajectory integration slows down with the XY position tracking error). If you improve the position tracking, the drone won’t stop descending.

Here’s the code that stops the integration: https://github.com/PX4/PX4-Autopilot/blob/b2f0c149ecb5614b0bc878d0b5359df659e98051/src/modules/flight_mode_manager/tasks/AutoLineSmoothVel/FlightTaskAutoLineSmoothVel.cpp#L458

The “current pitch_down” is generated by the velocity PID controller; So if this value is used to compute the pusher thrust, it will also be controller by the PID controller.

But, isn’t XY error a natural result of the current concept on windy days? Pusher is held at 0% throttle until the down-pitch limit is reached. Therefore, no matter how robust position controller I have, the aircraft will always be drifted towards downwind as long as the down-pitch limit is the same (taking into account that too large down-pitch limit can waste a lot of thrust on windy days).

My suggestion is having a Continuous Pusher Assist without checking if the down pitch is reached until being killed by the VT_FWD_THRUST_EN logic. And as you mentioned, when the pusher loss detection is also available, allow an “Emergency Down-Pitch Limit” in case off engine loss. The PID controller for the pusher motor should find the trim throttle level, which corresponds the drag due to wind resistance, and keep it until needing accelerating forward.

Alternative workaround: Do you think if I set VT_DWN_PITCH_MAX = 0, it will correspond to my suggestion conceptually?

I think you didn’t understand the logic completely. Let’s take an example:

Case 1: The velocity controller generates a forward thrust setpoint of 0.1 -> the corresponding down pitch is 3 degrees. Since the VT_DWN_PITCH_MAX = 5 degrees, the drone will pitch down 3 degrees without any pusher assist.

Case 2: The velocity controller generates a forward thrust setpoint of 0.8 -> the corresponding down pitch is 45 degrees. Since this is above VT_DWN_PITCH_MAX, the drone will not pitch at all and the pitch setpoint is converted back to a forward thrust (0.8) and multiplied by VT_FWD_THRUST_SC (e.g.: 0.5), so the normalized thrust sent to the pusher is 0.8 x 0.5 = 0.4. If tuned properly, the force produced by the pusher should be the same as the VTOL pitching 45 degrees in a non-windy day. The mapping does not need to be exact as the velocity PID controller will adjust the pusher depending on the error.

Yes, I did that as well as I didn’t want the VTOL to drop the nose when facing wind. It works really well (until you have a motor failure).


Now it is very clear. I will try VT_DWN_PITCH_MAX = 0. Thanks for you guidance!

allow an “Emergency Down-Pitch Limit” in case off engine loss.

Agree that that’s something important, and help in developing it would be very much appreciated!

Hello @bresch, @sfuhrer

If I change the code piece as following, would it help reducing the slowing down due to position error?

float time_stretch = 1.f - math::constrain(position_error * 0.5f, 0.f, 1.f);
float time_stretch = 1.f - math::constrain(position_error * 0.1f, 0.f, 1.f);

Yes, with that change, the slow-down will be 5 times less important.
If you want to avoid having a custom code that you need to maintain and port at each release, I would suggest that you create a parameter for it. This way, you would only need to change the parameter value for your vehicle config and you won’t need to have to maintain that code diff.

1 Like