airbound-develop: add 4575 rc8 fixes - #128
Conversation
- 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
This reverts commit ea58cdf.
Reduce the Roll angle P gain to 3.75
Greptile SummaryThis PR bundles several rc8 fixes for the Airbound tailsitter platform: a feedforward-scalar formula correction in the attitude controller, a new configurable VTOL pitch clip (
Confidence Score: 3/5The attitude controller feedforward fix and pitch-clip additions look correct, but the removal of yaw headroom limiting in AP_MotorsTailsitter leaves the yaw PID without anti-windup protection when tilt motors saturate — this is an active flight-control regression. The AP_MotorsTailsitter change silently drops limit.yaw signalling and removes the pitch_thrust constraint that guards tilt output range. In saturation scenarios the yaw integrator will wind up unchecked, producing sudden yaw kicks when motors come out of saturation. The rest of the PR — the feedforward scalar fix, PIT_CLIP_MAX, new Lua bindings, and the Lua script refactors — all look directionally correct, with the Lua issues being style and robustness notes rather than breaking defects. libraries/AP_Motors/AP_MotorsTailsitter.cpp needs the yaw headroom limiting and limit.yaw signalling restored; libraries/AP_HAL_ChibiOS/hwdef/Pixhawk6C-bdshot/scripts/autobailout.lua has several minor cleanup items; libraries/AP_Scripting/docs/docs.lua needs @return annotations corrected to reflect table returns. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[attitude_controller_run_quat] --> B{ts_enabled and not in_transition?}
B -- yes --> C[clamp pitch to PIT_CLIP_MAX]
B -- no --> D[skip clamp]
C --> E[thrust_heading_rotation_angles]
D --> E
E --> F{thrust_error_angle}
F -- gt 3T --> G[use gyro.z, reset yaw I]
F -- gt 2T --> H[feedforward_scalar 1 to 0]
F -- else --> I[full feedforward]
H --> J[ang_vel_body update]
I --> J
G --> J
J --> K[AP_MotorsTailsitter]
K --> L[tilt = pitch minus or plus yaw]
L --> M[Tilt servo commands]
subgraph Lua
N[autobailout update] --> O{autobailout_active?}
O -- no --> P[check pitch limits]
P -- triggered --> Q[switch to QLoiter]
O -- yes --> R{mode QLOITER?}
R -- no --> S[Manual Override]
R -- yes --> T{window stable?}
T -- yes --> U[recover to pre_bailout_mode]
T -- no --> V[keep monitoring]
end
%%{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"}}}%%
flowchart TD
A[attitude_controller_run_quat] --> B{ts_enabled and not in_transition?}
B -- yes --> C[clamp pitch to PIT_CLIP_MAX]
B -- no --> D[skip clamp]
C --> E[thrust_heading_rotation_angles]
D --> E
E --> F{thrust_error_angle}
F -- gt 3T --> G[use gyro.z, reset yaw I]
F -- gt 2T --> H[feedforward_scalar 1 to 0]
F -- else --> I[full feedforward]
H --> J[ang_vel_body update]
I --> J
G --> J
J --> K[AP_MotorsTailsitter]
K --> L[tilt = pitch minus or plus yaw]
L --> M[Tilt servo commands]
subgraph Lua
N[autobailout update] --> O{autobailout_active?}
O -- no --> P[check pitch limits]
P -- triggered --> Q[switch to QLoiter]
O -- yes --> R{mode QLOITER?}
R -- no --> S[Manual Override]
R -- yes --> T{window stable?}
T -- yes --> U[recover to pre_bailout_mode]
T -- no --> V[keep monitoring]
end
|
| // 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; |
There was a problem hiding this comment.
Yaw anti-windup and saturation limiting removed
The old code constrained pitch_thrust to [-1, 1], computed yaw headroom as the remaining budget, clamped yaw_thrust to that headroom, and set limit.yaw = true when clamping occurred. All three of those guard rails are now gone.
The limit.yaw flag is read by AP_AttitudeControl to prevent integrator windup: when it stays false, the yaw-rate PID integrator keeps accumulating even though the tilt motors are physically saturated. Once the motors come out of saturation the accumulated I-term causes a sudden yaw kick. Additionally, pitch_thrust is assigned from _pitch_in + _pitch_in_ff without any range constraint, so _tilt_left/_tilt_right can now exceed [-1, 1] when feedforward is active, sending out-of-range commands to the tilt servos.
| logger:write('AUTB', 'AvgErr,PeakAng,PitchDeg,QPit,QRateP', 'fffff', avg_err, peak_ang, pitch_deg, actual_vtol_pitch_deg, actual_vtol_pitch_rate) | ||
| end | ||
|
|
||
| is_vtol_flight = in_vtol_flight() |
There was a problem hiding this comment.
is_vtol_flight assigned to global scope
is_vtol_flight = in_vtol_flight() is missing the local keyword, making it an implicit global. ArduPilot Lua scripts share the global environment, so this leaks state between iterations and could interact with other scripts that happen to use the same name. Consistent with the many other local fixes elsewhere in this PR, this line should also be declared local.
| function quadplane:tailsitter_in_vtol_transition() end | ||
|
|
||
| -- desc | ||
| ---@return number -- roll_cd | ||
| ---@return number -- pitch_cd | ||
| ---@return number -- yaw_cd | ||
| function qp_att_desired() end | ||
|
|
||
| -- desc | ||
| ---@return number -- roll_cd | ||
| ---@return number -- pitch_cd | ||
| ---@return number -- yaw_cd | ||
| function qp_att_actual() end | ||
|
|
||
| -- desc | ||
| ---@return number -- roll_dps | ||
| ---@return number -- pitch_dps | ||
| ---@return number -- yaw_dps | ||
| function qp_angle_rate() end | ||
|
|
||
|
|
||
| --desc | ||
| ---@param axis integer | ||
| ---| '0' # Roll axis | ||
| ---| '1' # Pitch axis | ||
| ---| '2' # Yaw axis | ||
| ---@return number -- P |
There was a problem hiding this comment.
@return annotations describe multiple return values but bindings return a table
qp_att_desired, qp_att_actual, qp_angle_rate, and qp_rate_pid_info are all annotated as returning multiple number values (e.g., ---@return number -- roll_cd), but the C implementations in lua_bindings.cpp all call lua_newtable and return a single table with named fields. Any script that follows the annotations and unpacks with local r, p, y = qp_att_desired() will receive the table in r and nil in p and y. The autobailout script already uses the correct table-access style (desired.pitch_cd), so the annotations should be updated to reflect the actual return type.
No description provided.