INAV Blackbox Analysis: Tuning PIDs and Filters From Your Log
People run INAV for navigation: position hold, return to home, missions. All of it rests on the inner rate loop. If the gyro is noisy and the PIDs are off, the quad holds altitude worse, sways in POSHOLD and cooks its motors. Below: how to record a log worth analysing, which INAV settings do what, and what nine real INAV 6–8 logs showed in bbdoctor.
Logging setup: rate, raw gyro, motors
INAV sets the logging rate as a fraction of the loop rate: 1,000,000 / looptime × blackbox_rate_num / blackbox_rate_denom. With the standard looptime = 500 (2 kHz), 1/2 gives 1 kHz and 1/32 roughly 62 Hz. Two INAV 7.1 quads in our collection logged at 60 and 58 frames per second.
- 500 Hz or more. Motor and prop noise lives above 80 Hz, frame resonances usually from about 100 Hz. A log only shows frequencies up to half its rate, so a 60 Hz log stops at 30 Hz. bbdoctor runs its vibration and motor-noise checks only from 500 Hz. On paper 1/4 gives 500 Hz, but the real loop in our logs ran at 1890–1990 Hz, so 1/4 lands just under the gate. Use 1/2.
- GYRO_RAW. The gyro before filtering. Without it you can't separate frame vibration from filter behaviour, measure filter delay, or tell a dead sensor from a firmware glitch.
- MOTORS. The motor commands. Without them there's no motor noise, load balance or stick response, and bbdoctor rejects the log outright, as it did one of our INAV 7.0 samples (Matek H743).
- Storage. Onboard flash holds a few minutes at 1 kHz; an SD card has to keep up. One INAV 6.1.1 log from an H7 board lost 27% of its frames and had 6 gaps, so every number from it carries a caveat.
blackbox GYRO_RAW blackbox MOTORS set blackbox_rate_num = 1 set blackbox_rate_denom = 2 save
With a small flash chip, keep 500 Hz and fly short 30–60 s test flights instead. To pin down a resonance, record one short 1/1 log (2 kHz). General advice: the blackbox setup guide.
INAV 8 and newer log activeFlightModeFlags, the modes that were actually active, so ACRO is easy to tell from self-levelling and navigation modes. INAV 7 and older only log flightModeFlags, the mode switches that were on, and a switched-on navigation mode may never engage (no GPS fix, for example).
What to fly for the log
PIDs can only be judged from ACRO. In ANGLE, HORIZON and navigation modes the stick commands an angle; an angle loop sits between stick and rate loop, so the response says little about the PIDs. bbdoctor leaves those stretches out of the PID verdict. On the second flight of the H743 quad below (73 s, 78% ANGLE/HORIZON) the report covers noise, filters and load balance, but says nothing about overshoot: there is nothing to judge.
- 6–8 sharp rolls and flips, snapping the stick back to centre and holding it there for half a second. With fewer than six stops per axis bounce-back can't be checked; the good H743 log had one per axis.
- 5–8 clean throttle chops: climb at over 35% throttle, snap to zero, sticks centred for a second. A chop that runs into a flip is useless for propwash.
- A few punch-outs from hover to full throttle, plus some steady flying at different throttle levels for the noise map.
A large craft needs no flips: short, sharp tilts at a safe height will do. Leave navigation off.
INAV settings you tune from the log
| Setting | Default | What it does, when to touch it |
|---|---|---|
mc_p_roll, mc_i_roll, mc_d_roll (pitch the same) | 40 / 30 / 23 | Main PIDs. Overshoot from the P/D loop: less P or more D. I fights constant forces: an off-centre CG, wind. |
mc_p_yaw, mc_i_yaw, mc_d_yaw | 85 / 45 / 0 | Yaw D is zero, so the log has no axisD[2] field. |
mc_cd_roll, mc_cd_pitch, mc_cd_yaw | 60 | Control Derivative, INAV's feedforward, driven by stick speed. Logged as axisF. |
gyro_main_lpf_hz | 60 Hz | Main gyro lowpass (gyro_lpf_hz in the header). Lower is quieter but slower. |
dterm_lpf_hz, dterm_lpf_type | 110 Hz, PT2 | D-term lowpass. Hot motors with noise coming through D: lower by about 15%. |
dynamic_gyro_notch_enabled, dynamic_gyro_notch_min_hz, dynamic_gyro_notch_q | ON, 50 Hz, 120 | Dynamic notches (Matrix Filter). The lower limit must sit below the resonance, or the notch can't reach it. |
rpm_gyro_filter_enabled, rpm_gyro_min_hz | OFF, 100 Hz | Fed by ESC telemetry; enable only if it (usually a separate wire) delivers sensible RPM. |
setpoint_kalman_enabled, setpoint_kalman_q | ON, 100 | Kalman filter on the gyro. Higher q filters less, with less delay. |
d_boost_min, d_boost_max | 0.5 / 1.25 | D is scaled down (×0.5) on fast stick moves and up (×1.25) on sharp external disturbances. |
tpa_rate, tpa_breakpoint, tpa_on_yaw | 0 / 1500 / OFF | Above the breakpoint TPA scales down P, D and CD (FF); 0 = off. Overshoot or shakes only at high throttle: turn it on. |
mc_iterm_relax, mc_iterm_relax_cutoff | RP / 15 | Stops I winding up on fast stick moves. Bounce-back: cutoff 15 → 10; on yaw, mc_iterm_relax = RPY. |
antigravity_gain, antigravity_accelerator | 1 / 1 | Anti-gravity, where 1 means off. Nose dips on sharp throttle: set 2. |
airmode_type | STICK_CENTER | STICK_CENTER stops I growing at zero throttle with centred sticks. The INAV docs recommend THROTTLE_THRESHOLD for props up to 7". |
throttle_idle | 8 (%) | Motor idle. Propwash with a motor sitting at idle: +2. |
ez_enabled | OFF | EzTune: when ON, PIDs, filters and rates come from the ez_filter_hz, ez_response, ez_damping and other sliders, and manual edits get overwritten. |
Defaults are from INAV's Settings.md; confirm yours with get. Many never reach the log header: it has the PID strings, gyro_lpf_hz, dterm_lpf_hz, dynamicGyroNotchMinHz, TPA and rpm_gyro_*, but no d-boost, anti-gravity, I-term relax, airmode_type or any EzTune setting, and bbdoctor reconstructs throttle_idle from minthrottle. That's why the report says "check with get" for those. Save your current values first:
get mc_ get dterm_lpf get dynamic_gyro_notch get antigravity get mc_iterm_relax get throttle_idle get airmode_type
For the whole configuration, paste your diff all into the config check.
Real INAV logs and what they showed
INAV 7.1 at 60 Hz: no vibration, no PIDs
A Matek F722SE on 6S (flights of 213 and 171 seconds) and a SpeedyBee F7 V3 (26 seconds), both with blackbox_rate_denom = 32 on a 2 kHz loop: 60 and 58 frames per second. The F722SE wasn't logging GYRO_RAW either, and every flight was entirely ANGLE/HORIZON. Only 0–30 Hz is visible, so motor noise, resonances and filters are out of view, and the PIDs can't be judged twice over: wrong rate, wrong mode.
Still usable: the load split between motors (on the F722SE the right motors work 17% harder: the CG sits to the right, so check the battery and anything heavy off-centre), battery voltage under load, failsafe events and the crash timeline. These are slow processes; 60 Hz is enough.

INAV 8, Matek H743, 6S: a 117 Hz resonance and overshoot that isn't FF
A good log: 995 Hz, GYRO_RAW, 55 seconds of ACRO, with gains well above stock: roll P 80, I 22, D 32, FF 100; pitch 88 / 24 / 35 / 110.
- Raw noise above 80 Hz: roll 8.0, pitch 6.8, yaw 4.6 deg/s. bbdoctor's bands: under 4 is fine, 4–10 noisy, above 10 critical. Filtered: 1.07 deg/s at about 2.3 ms of filter delay, so the filters cope.
- A 117 Hz resonance on pitch only, 12 dB above the background and fixed at every throttle level: mechanical (figure below). The filters cut it by about 17 dB, but it still reaches the PID loop. At a 995 Hz logging rate the true frequency is ambiguous: 117 Hz, or 878 or 1112 Hz folded down. And
dynamicGyroNotchMinHzis 126 Hz here, so if the peak really is at 117 Hz the dynamic notch can't reach it: the logged notch positions (gyroPeakPitch[0..2], INAV 8) show the first pitch notch pinned at its floor, 125–127 Hz, for a quarter of the flight. Order: tighten the frame, stack, camera and antenna, record a short 1/1 log (2 kHz), then decide on a notch. - Motor noise of 2.9% (worst on M3); bbdoctor flags it from 2.5% and calls it critical from 4%. The logged PID terms show D carrying 4–4.5 times more of it than P, FF almost none. The report suggests
dterm_lpf_hz185 → 157. - Overshoot: 30% on roll (133 stick stretches, 90% range 24–36%), 25% on pitch. Damping ζ ≈ 0.42 and 0.41 against a healthy 0.6–0.9: the response dips 14% below target after the peak and rings at about 7 Hz. FF does only 22% (roll) and 19% (pitch) of the work and never leads the stick, so the P/D loop itself overshoots and lowering
mc_cd_*won't help. - Delay from setpoint to the roll response peak: 31 ms (27.7–33.6), against 4–12 ms for a crisp tune with feedforward. Don't raise FF to cut it while the axis overshoots.
- Propwash (0.6 deg/s, 12 clean chops of 15) and punch-outs (pitch 1.0°, roll 0.6°) are fine. Bounce-back couldn't be checked: one sharp stop per axis.
The report's logic: pitch P down 10%. Roll P stays, because the axis already responds with 31 ms of delay; roll D goes up 10% (32 → 35) only once the motor noise is gone, or the motors run hotter.
set dterm_lpf_hz = 157 set mc_p_pitch = 79 save
Check EzTune first, though. The filters in this log match the EzTune formula for ez_filter_hz = 190 exactly: gyro_lpf_hz 190, dterm_lpf_hz 5 Hz lower, the notch floor at two thirds (126) and notch Q 250. The pitch gains are 1.1 times roll, which is ez_axis_ratio 110. If get ez_enabled says ON, EzTune will overwrite the commands above. Either set ez_enabled = OFF (current PIDs and filters stay) and then apply them, or use the slider: ez_filter_hz 190 → 160 gives dterm_lpf_hz 155, but also drops the gyro lowpass to 160 Hz (more delay) and the notch floor to 106 Hz.
escRPM in this log is alive and follows the throttle, yet rpm_gyro_filter_enabled = 0. The RPM filter would remove some motor noise, but not the 117 Hz resonance, which doesn't move with motor speed.

INAV 8, BetaFPV F411, 1S whoop: D twelve times stronger than P
Ten seconds at 973 Hz with GYRO_RAW. Roll PID: P 17, I 86, D 50, FF 60; pitch 40 / 90 / 35 / 60. Roll D is three times P, while stock INAV has D 23 against P 40. In the log the roll D-term is 12 times stronger than P and carries almost all the motor noise: 5.5% on the motors (M4, critical), 22.1 deg/s of raw roll noise, 4.8 deg/s left after filtering. It looks like a typo or swapped values, and that's where the report starts:
set mc_d_roll = 35 save
Three more findings. The RPM filter is on (rpm_gyro_filter_enabled = 1), yet escRPM holds the same meaningless number all flight; so the filter apparently ran without RPM data. The M1+M4 diagonal works harder all the time (46%): the mixer is constantly correcting yaw, so look for a tilted motor or mismatched props. Propwash was 9.4 deg/s, but from only three clean chops (a confident verdict needs five), and in two of them the weakest motor sat at idle for 150 ms or more of the half-second window after the chop. That's not a lack of D; the flight controller has nothing left to brake with. If the next flight confirms it: throttle_idle 8 → 10 and airmode_type = THROTTLE_THRESHOLD. More in the propwash guide.
INAV 6.x: the filtered gyro dropped to zero while the raw gyro lived on
Two quads, both crashed. INAV 6.1.1 on an AocodaRC H7 Dual (3S): the filtered gyro reads a flat zero for 0.9 s as a failsafe fires, although RC packets keep arriving. INAV 6.0.0 on an iFlight Blitz F7 (6S): zero for 1.5 s, failsafe 1.4 s before a 9 g impact, throttle falling from 32% to 4%, and again RC packets still arriving. Both times the raw gyro kept seeing rotation: the sensor was fine, the zero came from the firmware.
bbdoctor calls it a freeze when all three gyro axes stay exactly constant for 0.3 s or more while airborne. Without GYRO_RAW you can't tell a firmware glitch from a sensor failure. What to do: update the firmware, check whether failsafe sits on a switch on your radio, and review failsafe_procedure. If it happens without a failsafe too, check the soldering and the FC's 3.3 V supply.
Tuning order for INAV
- Logging. 500 Hz or more, GYRO_RAW, MOTORS. Decide on EzTune: work its sliders, or set
ez_enabled = OFFand tune by hand. - Mechanics. Raw noise above 4 deg/s on roll or pitch, peaks that climb with throttle (props, motors), a peak fixed in frequency (frame): props, screws and a soft-mounted stack come first. Filters don't fix mechanics. More in the noise and filter guide.
- Filters. Motor noise of 2.5% or more and warm motors:
dterm_lpf_hz−15%. Noise still getting through:gyro_main_lpf_hz−15%. A resonance belowdynamic_gyro_notch_min_hz: lower the limit once a 2 kHz log confirms the frequency. Working ESC telemetry: enable the RPM filter. Little noise and cool motors: relax the filters slightly for less delay. - P and D. On overshoot, check FF's share first. If it's small, the overshoot is P/D: lower P, and with ζ below 0.6 and cool motors add D in 10% steps.
- I, relax, anti-gravity, TPA. Bounce-back:
mc_iterm_relax_cutoff15 → 10, then I −10%. Nose dips on sharp throttle:antigravity_gain = 2. Overshoot or shakes only at high throttle:tpa_rate0 → 20, or +15 if TPA is already on (in INAV it scales P, D and CD). - Propwash. A motor sitting at idle during chops:
throttle_idle+2 andairmode_type = THROTTLE_THRESHOLD, not more D. Airmode itself must be on:feature AIRMODEor the AIR MODE switch. - FF and stick smoothing last, once the loop stops overshooting.
One change per flight; feel the motors after each one. Reading the step response is covered in PID tuning from blackbox.
When to change nothing. A log below 500 Hz: leave the filters alone. A flight in ANGLE or a navigation mode: leave the PIDs alone. Fewer than five clean chops: don't treat propwash; fewer than six sharp stops per axis: leave relax and I alone. A noticeable share of lost frames: fly again. With raw noise under 4 deg/s, motor noise under 2.5% and damping of 0.6–0.9, leave the tune alone: more filtering adds delay, more D heats the motors.
How INAV logs differ from Betaflight
- Names. The header stores gains on one line,
rollPID:80,22,32,100meaning P, I, D and FF; the CLI has separatemc_p_roll,mc_i_roll,mc_d_rollandmc_cd_roll. Betaflight commands such asp_rollorf_rollwon't work. - Fields. The setpoint is
axisRate, notsetpoint; the PID terms areaxisP,axisD,axisF. bbdoctor uses them to split motor noise and overshoot between P, D and FF. - No per-motor RPM. The log can't point to one unbalanced motor, only to overall noise, resonances and load. Suspect a motor? Find it by swapping parts.
- Quad X motor numbering is the same: M1 rear right, M2 front right, M3 rear left, M4 front left.
Navigation only after the inner loop is clean
INAV's position and altitude controllers output a target angle and throttle, which the angle and rate loops you just tuned have to deliver. If roll overshoots by 30% and rings at 7 Hz, POSHOLD will sway, and tweaking nav_mc_pos_xy_p or nav_mc_vel_xy_p fixes the wrong loop. The order:
- A clean inner loop, judged from an ACRO log.
- Hover throttle: find the throttle (the
rcCommand[3]field) at which the quad hovers without climbing or sinking and setnav_mc_hover_thrto it (same 1000–2000 units); the altitude controller starts from it. - Then the altitude gains (
nav_mc_pos_z_p,nav_mc_vel_z_*) and position gains (nav_mc_pos_xy_p,nav_mc_vel_xy_*), one per flight.
bbdoctor analyses the inner loop, not the navigation controllers.
Check it automatically
bbdoctor analyses INAV blackbox logs (.txt and .bbl) online for free: everything measured in the cases above, with commands in INAV CLI syntax scaled from your current values. Since the thresholds were tuned on Betaflight FPV quads, the report warns that for large drones they are approximate. See a sample report.
FAQ
How do I log the raw gyro in INAV?
In the CLI type blackbox GYRO_RAW, then save. Typing blackbox on its own lists the fields being logged; MOTORS must be on too. The rate is set by blackbox_rate_num and blackbox_rate_denom: vibration and filter work needs 500 Hz or more, which with looptime 500 means 1/2 (about 1 kHz). In practice 1/4 lands just under 500 Hz, and the vibration checks stay off.
Does INAV have autotune for multirotors?
INAV's built-in AUTOTUNE mode is for fixed-wing aircraft. Multirotors are tuned by hand from the log, or the simple way with EzTune (ez_enabled), which derives PIDs and filters from a handful of sliders. With EzTune on, manual PID edits get overwritten.
What is mc_cd_roll in INAV?
Control Derivative, INAV's equivalent of Betaflight feedforward. It pushes the craft into a move based on how fast the stick moves, ahead of P. The default is 60 on every axis. In the log header it is the fourth number of rollPID; in the log data it is the axisF field.
Why is my INAV log recorded at 60 Hz?
The logging rate is the loop rate times blackbox_rate_num / blackbox_rate_denom. With looptime 500 (2 kHz) and a 1/32 ratio you get about 62 Hz, so the log only shows 0 to 30 Hz. Set blackbox_rate_num = 1 and blackbox_rate_denom = 2 for 1 kHz.
Updated: