ArduPilot Log Analysis: Vibration, Clipping, Filters and PIDs
Your ArduCopter won't hold altitude, drifts in Loiter, throws EKF warnings or buzzes after an autotune. Usually the root cause is vibration: the position estimate degrades and the autopilot fights something that isn't there. The order never changes: the right log → vibration and clipping → spectrum and notch → lowpass filters → PIDs. Below are the thresholds bbdoctor applies, with numbers from real ArduCopter logs.
Getting the right log and turning on fast logging
You need the onboard DataFlash .bin log (Mission Planner → DataFlash Logs → Download, or APM/LOGS on the SD card); a telemetry .tlog doesn't carry enough data. What gets logged is set by LOG_BITMASK. Five bits matter here:
| Bit | Name | Value | Why | In the default mask |
|---|---|---|---|---|
| 0 | ATTITUDE_FAST | 1 | ATT and RATE at loop rate (400 Hz), the target for PID analysis | no |
| 7 | IMU | 128 | gyro, accelerometer, VIBE; mandatory | yes |
| 10 | RCOUT | 1024 | motor outputs; mandatory | yes |
| 12 | PID | 4096 | P, I, D, FF terms in PIDR/PIDP/PIDY | from 4.6 |
| 19 | IMU_RAW | 524288 | raw gyro (GYR) at sensor rate | no |
The default mask is 176126 up to 4.5; 4.6 added the PID bit, making it 180222. In all ten ArduCopter logs in our test set (4.1 to 4.8-dev, fmuv2 to Pixhawk 6X, plus two SITL runs), IMU was logged at 25 Hz and RATE, RCOU and VIBE at 10 Hz: enough for VIBE and average motor loads, not for a spectrum, filter checks or the PID response.
In Mission Planner just tick ATTITUDE_FAST and IMU_RAW in LOG_BITMASK. When a log has no raw gyro, bbdoctor adds the missing bits to your current mask. For 176126:
LOG_BITMASK = 700415 INS_RAW_LOG_OPT = 9
From 180222, as in all our 4.7 logs, you get 704511. INS_RAW_LOG_OPT = 9 (primary gyro before and after filtering) arrived in 4.5; on the 4.3.7 logs bbdoctor suggests only LOG_BITMASK = 700415, since bit 19 alone enables raw logging there.
Logs grow dozens of times, and slow boards or cards drop data (bbdoctor reports "Gaps in the recording"); ArduPilot documents raw IMU logging for H7 boards, so on an F4 like the fmuv2 below expect gaps. Afterwards restore your old LOG_BITMASK and INS_RAW_LOG_OPT = 0.
Test flight, 3–5 minutes: hover, a smooth throttle sweep well above hover and back, a few short sharp stick inputs per axis at a safe height. No flips.
bbdoctor rejects non-copter logs and logs without IMU or RCOU (one real large-quad log had bit 7 set but no IMU messages: upload the full .bin, not a trimmed export). SITL logs (SIM_* parameters) skip the hardware checks. Logging for any firmware: the logging setup guide.
VIBE and clipping: two different signals
VIBE.VibeX, VibeY and VibeZ are the accelerometer's standard deviation in m/s², the average shaking. VIBE.Clip (Clip0–Clip2 on older versions) counts samples that hit the sensor's range limit; it accumulates from boot and isn't reset between flights. bbdoctor rates them like this:
- VIBE: 95th percentile per axis over the time in the air. Below 30 m/s² OK, 30–60 warning, 60 and up critical (thresholds from the ArduPilot docs);
- Clip: counter growth from the first takeoff to the last landing; above 0 is a warning, above 100 critical. Clips while arming or after the final touchdown don't count. The ArduPilot docs agree: ideally zero, a few from hard landings are tolerable, a steady climb is serious.
Why you need both: a real ArduCopter 4.7.0 log, fmuv2, 4S, seven flights, 414 s in the air.

VIBE passes, 29 against 30, yet it clipped 424 times (critical in bbdoctor), and flight by flight it's no fluke:
| Flight | Time in air | VIBE p95 X / Y / Z | Clip increase |
|---|---|---|---|
| 1 | 69 s | 16 / 19 / 24 | 22 |
| 2 | 69 s | 16 / 20 / 25 | 34 |
| 3 | 79 s | 20 / 23 / 26 | 47 |
| 4 | 73 s | 20 / 22 / 30 | 106 |
| 5 | 31 s | 22 / 22 / 28 | 35 |
| 6 | 15 s | 16 / 20 / 24 | 4 |
| 7 | 79 s | 22 / 20 / 32 | 176 |
- Clipping happens with "normal" VIBE. VIBE is an average; clipping catches peaks. Short knocks (a loose battery, a wire slapping the FC, a bad bearing) barely move the average but saturate the sensor, and the EKF gets garbage.
- A whole-log percentile hides the worst flight: Z is 29 overall, 32 in the last flight. Clips per minute: 19 in the first flight, 134 in the last. Something is working loose.
- It isn't punch-outs. Median throttle while clipping was 23%, the same as the whole flight, all in self-levelling modes. It's mechanical.
An octocopter (CubeOrangePlus, 4.5.7) clipped 64 times over the log but only 19 in flight, so bbdoctor warned about 19. A healthy Tarot X4 on 4.5.5 (figure below): X 3, Y 3, Z 7 m/s², Clip = 0.
| What you see | Likely cause | What to do |
|---|---|---|
| All axes high, rising with throttle | unbalanced props or bells | balance or replace props, check shafts and bearings |
| Z clearly above X and Y | flexible arms, motor mounts, FC isolation too stiff or soft | tighten motors and arms, check the FC soft mounts |
| One axis twice the other | something loose that way: GPS mast, landing gear, gimbal | secure it, check for play by hand |
| VIBE fine, Clip rises every flight | knocks: battery, wires, a prop touching | straps, a grip pad under the battery, wires away from the FC |
Until VIBE and clipping are fixed, leave filters and PIDs alone. To find the bad motor, see the motor vibration guide. A "Vibration compensation ON" message means the vibration failsafe (FS_VIBE_ENABLE, on by default) has already switched altitude hold to a vibration-tolerant estimate.
Gyro spectrum and the harmonic notch
With the raw gyro logged (GYR), bbdoctor builds the spectrum before and after filtering and looks for peaks that don't move with throttle: frame resonances. It says to tighten the frame and, as a stopgap, suggests the second notch, INS_HNTC2_*, in fixed mode, only when the frequency is unambiguous; if the peak may be an alias, it lists the candidates and asks for a short raw-gyro log instead. For a 140 Hz resonance:
INS_HNTC2_ENABLE = 1 INS_HNTC2_MODE = 0 INS_HNTC2_FREQ = 140 INS_HNTC2_BW = 70 INS_HNTC2_ATT = 40
The other source is the batch sampler (INS_LOG_BAT_MASK, INS_LOG_BAT_OPT, with the IMU_RAW bit off): 1024-sample bursts (ISBH/ISBD) that barely grow the log. bbdoctor doesn't read them yet; use ArduPilot's Filter Review web tool or the Mission Planner FFT. Here's the Tarot X4.

The notch runs in FFT mode (INS_HNTCH_MODE = 4). The strongest line is 67 Hz, then 134 and 202. 34 Hz looks like rotation (about 2000 rpm) and 67 Hz its second harmonic, the blade pass of a two-blade prop. But the FFT window ends at 62 Hz, and the FFT reported 25 Hz all flight, exactly FFT_MINHZ (the learned FFT_FREQ_HOVER is 25.0 too). It never found the motor line.
In FFT mode the notch never goes below INS_HNTCH_FREQ, here 35 Hz, so it sat there, plus a second notch at 70 Hz from INS_HNTCH_HMNCS = 3. By luck that covers the 34 and 67 Hz lines: against the 20 Hz lowpass alone, the filtered spectrum is about 10 dB lower at 34 Hz and 17 dB at 67 Hz, with nothing extra at 134 and 202. The notch works, but as a fixed one.
Which is the point: not everything you could fix needs fixing now. After the filters the 67, 134 and 202 Hz lines are 35–43 dB down, VIBE is 3/3/7, no clipping. But a heavier battery or other props will move the lines, and the FFT won't follow. Before the next AUTOTUNE I'd switch to a throttle-based notch:
INS_HNTCH_ENABLE = 1 INS_HNTCH_MODE = 1 INS_HNTCH_REF = 0.2 INS_HNTCH_FREQ = 67 INS_HNTCH_BW = 33 INS_HNTCH_HMNCS = 7
REF is hover throttle (MOT_THST_HOVER = 0.20), FREQ the line at hover, BW half of it, HMNCS = 7 harmonics 1–3: 67, 134, 201 Hz. With the default INS_HNTCH_FM_RAT = 1 the notch never drops below FREQ. The 34 Hz notch goes on purpose: that line barely clears the gyro noise floor, and a notch that low, near where a big copter's controller works, costs phase. To keep it: FREQ 34, BW 17, HMNCS 43 (harmonics 1, 2, 4, 6: 34, 67, 134, 202 Hz). Or stay in FFT mode and widen FFT_MINHZ/FFT_MAXHZ to include 67 Hz.
Choosing INS_HNTCH_MODE (0 fixed, 1 throttle, 2 RPM sensor, 3 ESC telemetry, 4 FFT): with RPM telemetry, 3. No telemetry but an F7/H7: FFT, once the log shows FTN1.PkAvg moving with throttle instead of sitting on FFT_MINHZ. A weak flight controller: throttle. In ESC, RPM and FFT modes FREQ is the lower limit and REF is 1; REF = 0 pins the notch at FREQ.
Lowpass filters: INS_GYRO_FILTER and ATC_RAT_*_FLTD
INS_GYRO_FILTER is the gyro lowpass, 20 Hz by default (the 4.7 log and the Tarot; the 4.3.7 log has 40). ATC_RAT_RLL_FLTD/_PIT_FLTD filter the D term (20 in the 4.7 log, 10 on the Tarot), FLTT the target, FLTE the error (2–2.5 Hz on yaw). Mission Planner's Initial Tune Parameters sets starting values by prop size: smaller props, higher cutoffs.
- Raise
INS_GYRO_FILTERonly once the notch removes the motor lines: less delay, crisper response. - Steps of 10–20%, a short flight after each; disarm, unplug the battery, feel the motors. Warm is fine; hot, go back.
- VIBE fine, filtered spectrum clean, flies well: leave the filters alone. On the Tarot I wouldn't touch them.
An analysis trap: a 25 Hz log shows motion only up to 12.5 Hz; anything faster folds back as a false low frequency. So bbdoctor runs no filter or PID checks on such logs and says so. More in the filter guide.
PIDs: what the log shows and when to use AUTOTUNE
The rate controller is ATC_RAT_RLL_P, _I, _D, _FF, and the same for PIT and YAW. bbdoctor compares the target RATE.RDes (and PDes, YDes) with the gyro: overshoot, lag, oscillation after a sharp input. RDes comes after input shaping: ATC_INPUT_TC softens it but doesn't change how well the gyro follows it, so this measures the rate loop itself. It needs 200 Hz logging; otherwise bbdoctor reports "PIDs can't be assessed from this log: gyro logged at 25 Hz" and gives the commands from the first section.
For ArduCopter the built-in AUTOTUNE is usually more reliable, but only once vibration and the notch are sorted:
- VIBE below 30, Clip not rising, notch set.
- AUTOTUNE on a switch; axes in
AUTOTUNE_AXES(1 roll, 2 pitch, 4 yaw; 7 all three), aggressiveness inAUTOTUNE_AGGR(0.075 in both logs above). - AltHold, Loiter or PosHold in calm air; several minutes per axis, so bring battery margin.
- To keep the result, land and disarm with the switch still on.
More ArduPilot advice bbdoctor gives when the log is fast enough:
- Response stronger at high throttle. Copters have no TPA in ArduPilot, so linearise thrust better:
MOT_THST_EXPO+0.05 (e.g. 0.65 → 0.7). No help? Lower P and D by 10% and re-run AUTOTUNE. - Propwash on chops with motors at minimum. Raise
MOT_SPIN_MINby 0.02, keeping it at least 0.03 aboveMOT_SPIN_ARM. The 4.7 log has 0.08 withMOT_SPIN_ARM0.04, so the advice would be 0.08 → 0.1. See the propwash guide.
Two things bbdoctor doesn't check. Voltage compensation: in the 4.7 log MOT_BAT_VOLT_MAX = 0 and MOTB.BatVolt sits at 1.00, so it's off and the loop weakens as the pack drains. For 4S:
MOT_BAT_VOLT_MAX = 16.8 MOT_BAT_VOLT_MIN = 13.2
That's 4.2 and 3.3 V per cell; set it before AUTOTUNE, as it changes the effective gain. And PIDR.Dmod: if it often drops below 1, the ATC_RAT_*_SMAX slew limiter is damping an oscillation and the gains are at the edge. In the 4.7 log it stays at 1.00 (sampled at 10 Hz, so very short dips could hide).
Motor outputs at 10 Hz: loads yes, noise no
Default logs record RCOU at 10 Hz; bbdoctor notes: "Motor outputs are logged at 10 Hz — average loads are visible, but not motor noise". What you still get:
- An off-centre CG. Average commands are compared side to side: 12% or more is a warning, above 30% critical. In another 4.7 log the rear motors ran at 62.1% versus 55.2% front, 13% more, a warning. In the clipping log M1–M4 averaged 44.4 / 46.9 / 40.2 / 46.0%, about 10% front to rear, below the threshold.
- A tilted motor: the motors spinning one way carry 12% more than the other pair.
Mind the order: on an ArduCopter Quad X, M1 is front right, M2 rear left, M3 front left, M4 rear right, unlike Betaflight.
Finding one vibrating motor takes RPM: bidirectional DShot (SERVO_BLH_BDMASK, DShot in MOT_PWM_TYPE, correct SERVO_BLH_POLES) or wired ESC telemetry. The Tarot has poles set to 28 but runs plain PWM, so no RPM. With RPM, bbdoctor compares the motors and the notch can use mode 3.
Failsafe and battery
After a crash, first check failsafe was configured at all; bbdoctor points to these parameters when it suspects a link or battery problem. The 4.7 log (4S):
FS_THR_ENABLE = 1 FS_THR_VALUE = 950 BATT_LOW_VOLT = 14.4 BATT_CRT_VOLT = 14.0 BATT_FS_LOW_ACT = 2 BATT_FS_CRT_ACT = 1
FS_THR_ENABLE = 1means RTL on signal loss.FS_THR_VALUEmust be below your transmitter's minimum throttle and above what the receiver outputs in failsafe. Test on the bench, props off.- 14.4 and 14.0 V are 3.6 and 3.5 V per cell; actions 2 (RTL) and 1 (land). The Tarot (6S, 30,000 mAh) uses 3.1 and 2.95 V per cell: fine for Li-ion, too low for LiPo.
- The voltage must stay low for
BATT_LOW_TIMER(10 s by default), so punch-outs don't trip it. If long climbs do, setBATT_FS_VOLTSRCto 1 (sag-compensated).
bbdoctor reports starting voltage, minimum under load and internal resistance. The 4.7 log: 4.11 V per cell at start, 3.76 V minimum under load (sustained 0.5 s), 3.91 V at the end, 13 A peak, about 1010 mAh, roughly 10 mΩ per cell (an estimate, since voltage and current are sampled separately).
Parameter names change between versions
| What | Old name | New name |
|---|---|---|
| Max roll/pitch/yaw acceleration | ATC_ACCEL_R_MAX etc., in cdeg/s² | ATC_ACC_R_MAX etc., in deg/s² (4.7) |
| Maximum lean angle | ANGLE_MAX, in centidegrees | ATC_ANGLE_MAX, in degrees (4.7) |
| ACRO rotation rate | ACRO_RP_P, a gain: ×45 = deg/s (up to 4.1) | ACRO_RP_RATE, in deg/s (4.2+) |
ANGLE_MAX = 3000 in the 4.5.5 log and ATC_ANGLE_MAX = 30 in the 4.7 log are the same 30°. The firmware converts values itself on upgrade; the trap is copying numbers by hand from an old log or forum post. Put the Tarot's ATC_ACCEL_R_MAX = 48000 into ATC_ACC_R_MAX instead of 480 and you ask for a hundred times the acceleration.
Checking it automatically
Upload your .bin to bbdoctor, free. It runs the checks above (logging, VIBE, clipping, motor loads, battery, plus spectrum and PIDs on fast logs), says what's missing and gives parameters as NAME = value. Batch sampler, FFT data, voltage compensation and Dmod are on you. Thresholds were tuned on FPV quads, so on large aircraft compare with earlier logs of the same airframe. See an example report; for PX4, the ULog guide.
FAQ
What VIBE levels are acceptable in ArduPilot?
Per the ArduPilot docs, below 30 m/s² is fine, 30–60 can hurt position and altitude hold, and above 60 nearly always does. Check Clip too: ideally the clipping counter doesn't rise at all, and a steady climb through the flight is a serious problem even when VIBE looks normal.
How do I log the raw gyro in ArduPilot?
On 4.5 and newer set INS_RAW_LOG_OPT = 9 (primary gyro, pre and post filter) and bit 19, IMU_RAW, in LOG_BITMASK; on 4.3–4.4 bit 19 alone. For PID analysis add bit 0, ATTITUDE_FAST. From the 4.5 default of 176126 that gives 700415, from the 4.6+ default of 180222 it gives 704511. Logs grow a lot, so use it for test flights.
Can I analyze a .tlog instead of a .bin?
No. A telemetry .tlog is recorded at a low rate and lacks the fields you need. Use the onboard DataFlash .bin log from the SD card or downloaded in Mission Planner (DataFlash Logs → Download).
Why does bbdoctor say PIDs can't be assessed from my log?
Because the gyro was logged below 200 Hz. A default ArduCopter log records IMU at 25 Hz and RATE at 10 Hz: enough for vibration and motor loads, not for the rate controller response. Enable bits 0 and 19 in LOG_BITMASK for a test flight, or tune with AUTOTUNE.
Updated: