bbdoctor
Drone diagnostics from logs: Betaflight, INAV, ArduPilot, PX4
RUENESPTUA

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:

BitNameValueWhyIn the default mask
0ATTITUDE_FAST1ATT and RATE at loop rate (400 Hz), the target for PID analysisno
7IMU128gyro, accelerometer, VIBE; mandatoryyes
10RCOUT1024motor outputs; mandatoryyes
12PID4096P, I, D, FF terms in PIDR/PIDP/PIDYfrom 4.6
19IMU_RAW524288raw gyro (GYR) at sensor rateno

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:

Why you need both: a real ArduCopter 4.7.0 log, fmuv2, 4S, seven flights, 414 s in the air.

VIBE X, Y and Z over seven ArduCopter 4.7 flights stay mostly below the 30 m/s² line while the Clip counter steps up in every flight to 424
ArduCopter 4.7.0, 4S, seven flights in one log (grey: on the ground; VIBE smoothed over 0.5 s). Black line: in-flight Clip growth, 424 events, 176 of them in the last flight.

VIBE passes, 29 against 30, yet it clipped 424 times (critical in bbdoctor), and flight by flight it's no fluke:

FlightTime in airVIBE p95 X / Y / ZClip increase
169 s16 / 19 / 2422
269 s16 / 20 / 2534
379 s20 / 23 / 2647
473 s20 / 22 / 30106
531 s22 / 22 / 2835
615 s16 / 20 / 244
779 s22 / 20 / 32176

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 seeLikely causeWhat to do
All axes high, rising with throttleunbalanced props or bellsbalance or replace props, check shafts and bearings
Z clearly above X and Yflexible arms, motor mounts, FC isolation too stiff or softtighten motors and arms, check the FC soft mounts
One axis twice the othersomething loose that way: GPS mast, landing gear, gimbalsecure it, check for play by hand
VIBE fine, Clip rises every flightknocks: battery, wires, a prop touchingstraps, 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.

Left: low, flat VIBE traces for a Tarot X4 around 3–7 m/s²; right: gyro spectrum before and after filtering with peaks at 34, 67, 134 and 202 Hz, the 25–62 Hz FFT search window and the notch sitting at 35 and 70 Hz
Tarot X4, ArduCopter 4.5.5, 6S. A: VIBE 3/3/7 m/s², Clip = 0. B: gyro spectrum from about 50 batch-sampler bursts (2025 Hz), grey before the filters, blue after. Orange: FFT search window; dashed: FTN1.PkAvg, what the FFT reported; dotted: where the notch actually sat.

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.

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:

  1. VIBE below 30, Clip not rising, notch set.
  2. AUTOTUNE on a switch; axes in AUTOTUNE_AXES (1 roll, 2 pitch, 4 yaw; 7 all three), aggressiveness in AUTOTUNE_AGGR (0.075 in both logs above).
  3. AltHold, Loiter or PosHold in calm air; several minutes per axis, so bring battery margin.
  4. To keep the result, land and disarm with the switch still on.

More ArduPilot advice bbdoctor gives when the log is fast enough:

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:

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

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

WhatOld nameNew name
Max roll/pitch/yaw accelerationATC_ACCEL_R_MAX etc., in cdeg/s²ATC_ACC_R_MAX etc., in deg/s² (4.7)
Maximum lean angleANGLE_MAX, in centidegreesATC_ANGLE_MAX, in degrees (4.7)
ACRO rotation rateACRO_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:

More guides