Skip to content

Add 4575 rc4 fixes to airbound-develop - #118

Draft
akshar-airbound wants to merge 8 commits into
airbound-developfrom
pr-airbound-4575-rc4-fixes
Draft

Add 4575 rc4 fixes to airbound-develop#118
akshar-airbound wants to merge 8 commits into
airbound-developfrom
pr-airbound-4575-rc4-fixes

Conversation

@akshar-airbound

@akshar-airbound akshar-airbound commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Reverts disarm delay changes added in pr-airbound-4575-rc3-fixes branch.

Notion Page: https://app.notion.com/p/airbound/Revert-disarm-delay-PR-109-38721adf4be980f09db1ffd435316ea8?source=copy_link

Note: This PR replaces #117
The branch pr-4575-rc3-fixes contains rc3 fixes. See 4575 build page
This branch reverts only the disarm delay change added to pr-airbound-4575-rc3 using #109

vigneshm-debug and others added 7 commits June 16, 2026 12:39
- AP_Scripting: expose rate PID info to Lua via get_rate_pid_info(axis)
- Adds lua_get_rate_pid_info() binding returning a table of PID fields
(P, I, D, FF, target, actual, error) for roll (0), pitch (1), or yaw (2)
rate controllers. Used to compute control effort (|P + D + FF|) from Lua.
- Add get_attitude_control() public accessor to QuadPlane
- Add despitch, roll and yaw
…ed pitch (#111)

* Remove controller desaturation in control effort
* Add desaturation logic for Desired servo tilt
* Add logging for VH Power
* Add hard limit for pitch angle setpoint
* Add new parameters in default.param
* Add logging for the position controller demanded pitch
---------

Co-authored-by: Manuraj P M <[email protected]>
* introduced parameter LND_DET_TIM that controls how many milliseconds before disarm is detected
* add disarm watchdog and disable weathervane after touchdown
* Weathervane disable logic changed
* expose land detection timing as params Q_LND_RELAX_MS and Q_LND_LLIM_MS
---------

Co-authored-by: Stefard100 <[email protected]>
* Fix feedforward_scalar calculation when thrust angle error exceeds limits in AC_AttitudeControl.cpp
* add resume after autobailout
@akshar-airbound
akshar-airbound marked this pull request as draft June 22, 2026 06:05
@greptile-apps

greptile-apps Bot commented Jun 22, 2026

Copy link
Copy Markdown

Greptile Summary

This PR bumps the firmware version to rc3-fixes and adds a set of flight-control improvements for a tailsitter quadplane: a configurable pitch-angle hard-clip in the attitude controller, a corrected feedforward scalar calculation, a new servo desaturation block in Tailsitter::output(), expanded PHID logging, new Lua scripting bindings for attitude/rate diagnostics, and significant enhancements to the autobailout Lua script (rolling-window pitch metrics and automatic mode recovery).

  • AP_MotorsTailsitter: The motors-level thrust-vectoring saturation logic (including the limit.yaw flag) is fully removed; saturation responsibility shifts to Tailsitter::output(), but the limit.yaw anti-windup signal is never restored, leaving the yaw PID integrator unguarded during saturation.
  • Tailsitter::output() desaturation: The new block correctly zeros yaw headroom when pitch saturates, but uses the unclipped pitch_phi instead of pitch_phi_limited for the final servo values, causing inaccurate post-saturation logged outputs.
  • AC_AttitudeControl: The feedforward scalar fix is correct; the pitch-clip block does not also constrain _ang_vel_target.y, which can cause a transient at the clip boundary.

Confidence Score: 3/5

Not safe to merge as-is: the removal of limit.yaw in AP_MotorsTailsitter leaves yaw integrator windup unguarded whenever the servos saturate, which can degrade yaw authority in flight.

The most impactful change — moving servo saturation from the motors library to Tailsitter::output() — breaks the anti-windup feedback loop that the attitude controller relies on. The limit.yaw flag is never set anywhere after the refactor, so any yaw saturation event will silently wind up the I-term. The desaturation arithmetic bug in tailsitter.cpp (pitch_phi vs pitch_phi_limited) is a secondary concern since the SRV_Channels framework still clips the hardware output, but it corrupts the logged post-saturation values. The feedforward scalar fix and pitch-clip parameter are well-motivated changes, and the autobailout/Lua additions look solid.

libraries/AP_Motors/AP_MotorsTailsitter.cpp (limit.yaw removal) and ArduPlane/tailsitter.cpp (desaturation output calculation) need the most attention before merging.

Important Files Changed

Filename Overview
libraries/AP_Motors/AP_MotorsTailsitter.cpp Removes thrust-vectoring saturation and the limit.yaw flag entirely; yaw integrator anti-windup is now broken because the motors library never signals saturation back to the attitude controller.
ArduPlane/tailsitter.cpp Adds controller desaturation block and expanded PHID log message; desaturation uses unclipped pitch_phi for final tilt outputs, so logged post-saturation values are inaccurate when pitch is saturated.
libraries/AC_AttitudeControl/AC_AttitudeControl.cpp Adds PIT_CLIP_MAX pitch-angle clamping for VTOL and fixes an inverted feedforward scalar; pitch clip does not update _ang_vel_target.y, risking a transient at the clip boundary.
libraries/AP_HAL_ChibiOS/hwdef/Pixhawk6C-bdshot/scripts/autobailout.lua Significant expansion: adds rolling-window pitch diagnostics, auto-recovery back to pre-bailout mode, rate-limited GCS warnings, and moves LOOP_MS to a tunable parameter; logic appears sound.
libraries/AP_Scripting/lua_bindings.cpp Adds four new Lua bindings exposing attitude target, actual Euler angles, rate EF targets, and rate PID info for ArduPlane+QuadPlane builds; implementation is correctly guarded.
libraries/AP_Scripting/lua_bindings.h New function declarations added without the same #if APM_BUILD_TYPE(APM_BUILD_ArduPlane) && HAL_QUADPLANE_ENABLED guard used in the .cpp, risking link errors in non-ArduPlane builds.
libraries/AC_AttitudeControl/AC_AttitudeControl.h Adds _att_max_pit AP_Float member for the new pitch-clip parameter; straightforward addition consistent with existing members.
ArduPlane/quadplane.h Exposes get_attitude_control() and get_ahrs_view() accessors used by the new Lua bindings; straightforward and non-breaking.
libraries/AP_Scripting/generator/description/bindings.desc Registers four new global Lua functions with correct ArduPlane+QuadPlane build dependency guards.
libraries/AP_HAL_ChibiOS/hwdef/Pixhawk6C-bdshot/defaults.parm Adds default value for the new Q_A_PIT_CLIP_MAX parameter at 25 degrees, matching the AC_AttitudeControl default.
ArduPlane/version.h Version string bumped from rc2 to rc3-fixes.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant AC as AC_AttitudeControl
    participant MT as AP_MotorsTailsitter
    participant TS as Tailsitter::output()
    participant SRV as SRV_Channels

    AC->>MT: output_armed_stabilizing()
    Note over MT: pitch_thrust, yaw_thrust → _tilt_left/_tilt_right<br/>(no saturation, limit.yaw never set)
    MT->>SRV: set_output_scaled(tiltLeft, _tilt_left × 4500)
    MT->>SRV: set_output_scaled(tiltRight, _tilt_right × 4500)

    TS->>SRV: get_output_scaled(tiltLeft/Right)
    Note over TS: Apply vectored_hover_gain + extra_elevator
    Note over TS: Desaturation block:<br/>pitch_phi_limited = clamp(pitch_phi, ±4500)<br/>yaw headroom = 4500 − |pitch_phi_limited|<br/>tilt = pitch_phi ± yaw_phi_limited  ⚠ uses pitch_phi not pitch_phi_limited
    TS->>SRV: set_output_scaled(tiltLeft, tilt_left)
    TS->>SRV: set_output_scaled(tiltRight, tilt_right)
    Note over AC: limit.yaw never set →<br/>yaw I-term winds up silently
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant AC as AC_AttitudeControl
    participant MT as AP_MotorsTailsitter
    participant TS as Tailsitter::output()
    participant SRV as SRV_Channels

    AC->>MT: output_armed_stabilizing()
    Note over MT: pitch_thrust, yaw_thrust → _tilt_left/_tilt_right<br/>(no saturation, limit.yaw never set)
    MT->>SRV: set_output_scaled(tiltLeft, _tilt_left × 4500)
    MT->>SRV: set_output_scaled(tiltRight, _tilt_right × 4500)

    TS->>SRV: get_output_scaled(tiltLeft/Right)
    Note over TS: Apply vectored_hover_gain + extra_elevator
    Note over TS: Desaturation block:<br/>pitch_phi_limited = clamp(pitch_phi, ±4500)<br/>yaw headroom = 4500 − |pitch_phi_limited|<br/>tilt = pitch_phi ± yaw_phi_limited  ⚠ uses pitch_phi not pitch_phi_limited
    TS->>SRV: set_output_scaled(tiltLeft, tilt_left)
    TS->>SRV: set_output_scaled(tiltRight, tilt_right)
    Note over AC: limit.yaw never set →<br/>yaw I-term winds up silently
Loading

Reviews (1): Last reviewed commit: "Revert "Fix reduce disarm delay (#109)"" | Re-trigger Greptile

Comment on lines 212 to +214
// thrust vectoring
pitch_thrust = constrain_float(pitch_thrust, -1.0f, 1.0f);
float yaw_headroom = 1.0f - fabsf(pitch_thrust);
float yaw_thrust_limited = constrain_float(yaw_thrust, -yaw_headroom, yaw_headroom);
if (fabsf(yaw_thrust_limited) < fabsf(yaw_thrust)) {
limit.yaw = true;
}
_tilt_left = pitch_thrust - yaw_thrust_limited;
_tilt_right = pitch_thrust + yaw_thrust_limited;
_tilt_left = pitch_thrust - yaw_thrust;
_tilt_right = pitch_thrust + yaw_thrust;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Missing limit.yaw flag after saturation removal

The old code set limit.yaw = true whenever yaw thrust was clipped to its headroom. That flag is read by AC_AttitudeControl to suppress yaw integrator accumulation during saturation. The new code removes the saturation entirely here and relies on tailsitter.cpp to clamp servo outputs — but tailsitter.cpp runs after the motors library returns, so it never feeds limit.yaw back to the attitude controller. When yaw is saturated at the servo level, the yaw PID I-term will keep winding up unabated, potentially causing yaw oscillations or a persistent heading error after the saturation clears.

Comment thread ArduPlane/tailsitter.cpp
Comment on lines +585 to +586
tilt_left = pitch_phi - yaw_phi_limited;
tilt_right = pitch_phi + yaw_phi_limited;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Desaturation uses unsaturated pitch_phi for final output

When pitch_phi > 4500, pitch_phi_limited is clamped to 4500 and yaw_phi_headroom collapses to 0. But tilt_left and tilt_right are then set to pitch_phi - 0 = pitch_phi, not pitch_phi_limited. The outputs can exceed ±4500 centidegrees whenever pitch is saturated. Physical servo movement is ultimately clamped by the SRV_Channels framework, but the values stored in the SRV channel, used for logging (DesLPst, DesRPst), and any downstream consumers are incorrect — they show an unsaturated pitch value when the intent of the block is to log the post-saturation command.

Suggested change
tilt_left = pitch_phi - yaw_phi_limited;
tilt_right = pitch_phi + yaw_phi_limited;
tilt_left = pitch_phi_limited - yaw_phi_limited;
tilt_right = pitch_phi_limited + yaw_phi_limited;

Comment on lines +786 to +791
if(_ts_enabled && !_ts_in_transition){
Vector3f euler_sp;
_attitude_target.to_euler(euler_sp.x, euler_sp.y, euler_sp.z);
euler_sp.y = constrain_float(euler_sp.y,radians(-_att_max_pit),radians(_att_max_pit));
_attitude_target.from_euler(euler_sp.x, euler_sp.y, euler_sp.z);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 _ang_vel_target.y not updated alongside pitch quaternion clipping

The attitude relaxation code immediately above (line ~782) clips both euler_sp.y and _ang_vel_target.y together before rebuilding the quaternion. The new pitch-clipping block clips euler_sp.y inside the quaternion but leaves _ang_vel_target.y at its pre-clip value. When the pitch target is being actively limited, the quaternion encodes one pitch and the feed-forward angular velocity encodes a different (higher) pitch rate, creating a brief velocity-attitude mismatch that can produce an overshoot impulse at the clip boundary.

Comment on lines +30 to +33
int lua_get_rate_pid_info(lua_State *L);
int lua_get_att_target_euler_cd(lua_State *L);
int lua_get_rate_ef_targets(lua_State *L);
int lua_get_actual_euler_cd(lua_State *L);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 New declarations lack the same conditional compilation guard used in the implementation

In lua_bindings.cpp the four new functions are wrapped in #if APM_BUILD_TYPE(APM_BUILD_ArduPlane) && HAL_QUADPLANE_ENABLED, but their declarations here are unconditional. Any non-ArduPlane build that includes this header and tries to link against these symbols will fail at link time. Wrapping the declarations in the same guard keeps the two files consistent.

Suggested change
int lua_get_rate_pid_info(lua_State *L);
int lua_get_att_target_euler_cd(lua_State *L);
int lua_get_rate_ef_targets(lua_State *L);
int lua_get_actual_euler_cd(lua_State *L);
#if APM_BUILD_TYPE(APM_BUILD_ArduPlane) && HAL_QUADPLANE_ENABLED
int lua_get_rate_pid_info(lua_State *L);
int lua_get_att_target_euler_cd(lua_State *L);
int lua_get_rate_ef_targets(lua_State *L);
int lua_get_actual_euler_cd(lua_State *L);
#endif

@akshar-airbound akshar-airbound changed the title Add 4575 rc4 fixes Add 4575 rc4 fixes to airbound-develop Jun 30, 2026
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.

3 participants