ME 2801 — Introduction to Feedback Control
  • Home
  • Syllabus
  • Schedule
  • Assignments
  • Autopilot

On this page

  • Architecture
    • Simpified Ardu Control
    • Simpler Ardu Control
    • ArduRover documentation diagram
    • Details for both channels
  • Logged channels — a clarification on naming
  • Speed (Surge) Control
    • Design
    • Parameters — ATC_SPEED_* group
    • DataFlash log channels
    • Step-response setup for this lab
  • Yaw-Rate (Steering) Control
    • Design
    • Cascaded heading controller (not in ACRO)
    • Parameters — ATC_STR_RAT_* group
    • DataFlash log channels
    • Step-response setup for this lab
  • Restoring normal operation
  • Source references

Stabilization Layer — Speed and Yaw-Rate PID

← Back to Autopilot

For the dense per-parameter reference (units, ranges, vehicle values, source-code anchors for every ATC_* parameter on this page), see ATC parameter reference. This page focuses on how the loops are wired together; that page is the look-up table.

The stabilization layer is the lowest level of ArduRover’s control hierarchy. Two independent PID loops, one for speed (throttle channel) and one for yaw rate (steering channel), translate the pilot’s high-level commands into actuator outputs. Higher-level autonomous modes (HOLD, LOITER, AUTO) wrap additional outer loops around these, but in ACRO mode the pilot’s stick deflections become the setpoints to the stabilization PIDs directly. That makes ACRO the right mode for closed-loop step-response testing.

Architecture

Simpified Ardu Control

Both stabilization loops share the same generic structure: a setpoint enters the loop, gets compared against a measurement to form an error, and the PID + feedforward block computes the actuator output. For our purposes, we can consider a simplified version of the ArduRover architecture. The additional complexity is discussed further below.

Simplified ArduRover PID control loop.

Simplified ArduRover PID control loop.
  • Stick → setpoint scaling. The controller’s input is a target value (also known as a setpoint, command, reference, or desired value). The pilot provides this target through the R/C sticks: each stick’s PWM signal is normalized to a stick input in the range [−1, +1], then multiplied by a scaling parameter (CRUISE_SPEED for the speed channel, ACRO_TURN_RATE for the yaw-rate channel) to produce the setpoint in physical units.
    • We set these scaling values slightly above the maximum response you actually want from the boat so the full stick range maps to the full useful range of the plant. For our baseline setup CRUISE_SPEED = 5 m/s and ACRO_TURN_RATE = 57.3 deg/s.
      • NOTE for AY26Q3. The instructors did not change the default value of this parameter during pre-lab prep. Consequently in the Lab 2 results and the provided baseline .param you can see the effect of having this set incorrectly. The setpoint is much higher than the boat can achieve, so the measured response plateaus far below the commanded value, resulting in a large steady-state error. The procedure has students reduce ACRO_TURN_RATE to a value the boat can physically achieve.
    • ACRO_TURN_RATE is specified in deg/s, but ArduRover converts it to rad/s before passing it into the yaw-rate loop. Logged setpoints and measurements in the yaw channel are in rad/s.
  • PID controller with separate P, I, D, and FF terms. The gain params are: ATC_SPEED_P = 0.2, ATC_SPEED_I = 0.2, ATC_SPEED_D = 0, ATC_SPEED_FF = 0; ATC_STR_RAT_P = 0.2, ATC_STR_RAT_I = 0.2, ATC_STR_RAT_D = 0, ATC_STR_RAT_FF = 0.
    • *_IMAX caps the I-term contribution to the controller output, providing anti-windup. Baseline values: ATC_SPEED_IMAX = 1.0 and ATC_STR_RAT_IMAX = 1.0 (the maximum normalized actuator output), so the clamp is permissive and rarely active in practice.
    • *_FLTD low-pass filters the derivative term to suppress noise amplification — standard in any practical D implementation. Baseline values: ATC_SPEED_FLTD = 0 Hz and ATC_STR_RAT_FLTD = 0 Hz (filter disabled). Since ATC_*_D = 0 on this vehicle the derivative term is inactive anyway, so the filter setting has no effect at the baseline.

Simpler Ardu Control

This section provides detail of some (but not all) of the additional features in the implementation.

Generic PID block diagram with setpoint scaling, acceleration limiter, target LPF, error junction, error LPF, PID controller, output sum, plant, and feedback loop, with a feedforward branch from the setpoint to the output sum.

Generic PID control loop with feedforward and setpoint shaping.
  • Rate limiter on the commanded setpoint (ATC_ACCEL_MAX / ATC_STR_ACC_MAX). Limits the rate of change of the setpoint, ramping a stick step at the maximum rate instead of letting it jump instantaneously. Baseline values: ATC_ACCEL_MAX = 10 m/s² (speed), ATC_DECEL_MAX = 0 (falls back to ACCEL_MAX), ATC_STR_ACC_MAX = 0 deg/s² (yaw — already disabled). For step-response analysis we want to see the loop’s true step response, so the lab also disables the speed-channel limiter (ATC_ACCEL_MAX = 0).

    • NOTE for AY26Q3. Our goal is to effectively turn this off. This is done in the baseline .param by setting ATC_ACCEL_MAX = 0 and ATC_STR_ACC_MAX = 0. If you forget to do this, the speed setpoint will ramp up at 10 m/s² instead of stepping, which is not a show-stopper but makes the analysis more complicated.
    • Optional deep dive: the input_filtering_demo live script (source) compares a linear low-pass filter against a non-linear rate limiter as command-shaping elements.
  • Target low-pass filter (*_FLTT) softens setpoint steps before they enter the loop. Baseline values: ATC_SPEED_FLTT = 0 and ATC_STR_RAT_FLTT = 0 — the target filter is disabled on this vehicle, so the (rate-limited) setpoint enters the loop with no further smoothing.

  • Error low-pass filter (*_FLTE) attenuates measurement noise on the error before it reaches the PID. Baseline values: ATC_SPEED_FLTE = 10 Hz and ATC_STR_RAT_FLTE = 10 Hz. For the speed loop, 10 Hz is well above the GPS-limited information bandwidth (~5 Hz), so it has little practical effect there; on the yaw loop it removes high-frequency gyro noise without affecting the loop dynamics.

ArduRover documentation diagram

ArduPilot’s documentation gives this block diagram of the throttle/speed controller:

Rover throttle / speed controller (from the ArduPilot Rover docs)

It is the same generic structure with ArduRover’s specific parameter names attached. The yaw-rate loop has the same shape with ATC_STR_RAT_* substituted for the ATC_SPEED_* parameters.

Details for both channels

The diagram below shows both ArduRover loops side-by-side, with the actual ArduPilot logged signals on each wire and parameter names on each tunable block. Two notes before you read it:

  1. The two channels are not symmetric. The speed loop adds a CRUISE_THROTTLE baseline FF on the output sum that the yaw loop does not; the rate-limiter parameters have different units (m/s² vs deg/s²); and the loop bandwidths are very different (constrained by GPS update rate for speed, by vehicle dynamics for yaw).
  2. Signal and parameter names do not follow a strict convention — neither across channels (ATC_SPEED_* vs ATC_STR_RAT_*) nor within a single channel’s logged signals (THR_DesSpeed vs STER_DesTurnRate; PIDA_* for speed but PIDS_* for steering, where the S is for steering). This is just the way ArduRover names things; the per-channel sections below clarify the mapping.

The diagram’s purpose is to enumerate every signal (logged channel) and parameter (ATC_*) that is relevant to the stabilization layer.

USV stabilization layer block diagram showing speed and yaw-rate PID loops

Speed and yaw-rate stabilization loops

For closed-loop step-response experiments in Lab 2, several of these features are intentionally disabled (acceleration limiters off, throttle baseline off, FF off in the Base case) so that the response captures the PID dynamics alone. See the per-channel quick references below.

Logged channels — a clarification on naming

The signal names referenced throughout this page (THR_DesSpeed, STER_TurnRate, RCOU_C3, PIDA_*, PIDS_*) are ArduPilot DataFlash log message types: the binary .BIN log format that ArduPilot writes to the SD card during a flight/run. - DataFlash log (BIN file) — onboard binary log, complete record of internal state. We extract these with bin2mat.py and analyze them in MATLAB. —

Speed (Surge) Control

Design

Single-input, single-output PID + feedforward + baseline feedforward.

Loop element Source / value
Setpoint RC throttle stick ([−1, +1]) × CRUISE_SPEED (m/s)
Measurement GPS_Spd — GPS ground speed (m/s, ~5 Hz)
Output Throttle command, normalized [−1, +1] → PWM via RCOU_C3
Plant USV surge dynamics (thruster + hull drag)

Why these inputs/outputs make sense for the marine vehicle:

  • GPS speed as feedback — boats lack a wheel encoder, and the body-frame velocity from the IMU drifts. GPS gives a clean, slow ground-truth measurement. The 5 Hz update rate is one of the dominant time constants in this loop and shapes what kinds of dynamics the PID can possibly track.
  • Reversible throttle — with ATC_BRAKE = 1, the controller can command negative motor output to actively decelerate. Without it, deceleration relies entirely on hydrodynamic drag.

Parameters — ATC_SPEED_* group

Tunable PID gains (the values students change in Lab 2):

Parameter Description Default Vehicle Units
ATC_SPEED_P Proportional gain 0.20 1.0 (motor)/(m/s)
ATC_SPEED_I Integral gain (drives steady-state error to zero) 0.20 0.2 (motor)/(m/s·s)
ATC_SPEED_D Derivative gain (rarely useful — GPS-noisy) 0.00 0 (motor·s)/(m/s)
ATC_SPEED_FF Feed-forward, output ∝ setpoint 0.0 0 (motor)/(m/s)

Other parameters (preset; mostly disabled for the step-response experiments):

Parameter Description Default Vehicle Units
ATC_SPEED_IMAX Anti-windup clamp on I-term contribution 1.00 1.0 normalized
ATC_SPEED_FLTT Low-pass cutoff on target 0 (off) 0 Hz
ATC_SPEED_FLTE Low-pass cutoff on error 10 10 Hz
ATC_SPEED_FLTD Low-pass cutoff on derivative 0 (off) 0 Hz
ATC_SPEED_SMAX Slew-rate limit on PID output (anti-oscillation) 0 (disabled) 0 —
ATC_ACCEL_MAX Acceleration limiter on the commanded speed setpoint 1.0 1.0 m/s²
ATC_DECEL_MAX Deceleration limit; if 0, falls back to ATC_ACCEL_MAX 0 0 m/s²
ATC_BRAKE Allow negative motor output for active braking 1 1 bool
ATC_STOP_SPEED Below this speed, motor output is forced to zero 0.1 0.1 m/s
CRUISE_SPEED Stick-to-speed scaling (sets full-stick speed in ACRO) — — m/s
CRUISE_THROTTLE Baseline throttle FF added at the output sum — — normalized

DataFlash log channels

Channel Description Units
THR_DesSpeed Speed setpoint (after input filter) m/s
GPS_Spd Measured speed reported by the GPS receiver (~5 Hz) m/s
RCOU_C3 Throttle command sent to actuator PWM
PIDA_Tar PID’s internal target (after rate limiting, when active) m/s
PIDA_Act PID’s input measurement (sampled at the PID loop rate) m/s
PIDA_Err Target − Act, after error filter m/s
PIDA_P, _I, _D, _FF Individual PID term outputs normalized
PIDA_DFF, _Dmod, _SRate, _Flags Auxiliary fields (advanced features and limiters) —

ArduPilot does not log a separate Out field; the total controller output is P + I + D + FF (optionally + DFF). THR_DesSpeed and PIDA_Tar differ only when an upstream filter or rate limiter is active. With the lab settings (acceleration limiters disabled, FLTT off), the two are essentially identical.

A note on GPS_Spd vs PIDA_Act

These look like the same quantity (and they are, almost) but they’re sampled differently and routed through different filters before the PID consumes them.

  • GPS_Spd is the ground-speed estimate produced inside the GPS receiver itself, derived primarily from the Doppler shift of the satellite carrier signals (and to a lesser extent from the time derivative of position fixes). It logs at the GPS message rate, set by GPS1_RATE_MS (≈ 5 Hz on this vehicle). The receiver-internal estimate is reasonably clean at moderate-to-high speeds but degrades at low speeds (poor Doppler SNR), in multipath environments (near docks, hulls, sea walls), and during brief signal dropouts.
  • PIDA_Act is the value the speed PID actually consumes as its measurement input each iteration. ArduRover sources it from the EKF velocity estimate, which fuses GPS speed with body-frame IMU acceleration. It is sampled at the PID loop rate (~25–50 Hz), so the channel logs at that higher rate.

The practical implication for tuning: even though PIDA_Act updates fast, its information bandwidth is still capped by the underlying GPS update (≈ 5 Hz). Pushing the surge-loop bandwidth above that ceiling buys little and tends to amplify GPS noise into the actuator command.

Step-response setup for this lab

Setting Lab value Why
ATC_ACCEL_MAX 0 Disable rate limiter — let the setpoint be a true step
CRUISE_THROTTLE 0 Strip the baseline FF so the response is from the PID alone
ATC_SPEED_FF 0 for Base FF restored in FeedForward; tuned with PID in Tuned

Yaw-Rate (Steering) Control

Design

Single-input, single-output PID + feedforward. Same structure as the speed loop, with rudder/skid-steer command in place of throttle.

Loop element Source / value
Setpoint RC steering stick ([−1, +1]) × ACRO_TURN_RATE (deg/s, internally rad/s)
Measurement STER_TurnRate — body-frame yaw rate from EKF (rad/s)
Output Steering command, normalized [−1, +1] → PWM via RCOU_C1
Plant USV yaw dynamics (rudder + hull)

Why these matter for the marine vehicle:

  • EKF yaw rate as feedback — the IMU gyro provides a fast, accurate yaw rate measurement; the EKF (STER_*) blends gyro with magnetometer/GPS heading to suppress bias drift. Yaw rate updates much faster than the GPS speed signal in the surge loop, so the bandwidth ceiling of the yaw loop is set by vehicle dynamics, not measurement.
  • Strong feedforward by default — for a single-rudder boat, the steady rudder needed to hold a given yaw rate is approximately linear in the desired rate. The vehicle ships with ATC_STR_RAT_FF = 2.0 (10× the source default), reflecting that this contributes the majority of the open-loop control authority.

Cascaded heading controller (not in ACRO)

In autonomous modes (HOLD, LOITER, AUTO), an outer-loop heading controller (ATC_STR_ANG_P) wraps the yaw-rate loop, converting heading error to a desired yaw rate. ACRO bypasses that outer loop: the pilot stick commands yaw rate directly, so we tune only the inner rate loop in this lab.

Parameters — ATC_STR_RAT_* group

Tunable PID gains (the values students change in Lab 2):

Parameter Description Default Vehicle Units
ATC_STR_RAT_P Proportional gain 0.20 0.2 (motor)/(rad/s)
ATC_STR_RAT_I Integral gain (eliminates steady-state offset) 0.20 0.2 (motor)/(rad/s·s)
ATC_STR_RAT_D Derivative gain (use sparingly; yaw rate is already a derivative of heading) 0.00 0 (motor·s)/(rad/s)
ATC_STR_RAT_FF Feed-forward, output ∝ desired rate 0.20 2.0 (motor)/(rad/s)

Other parameters (preset; mostly disabled for the step-response experiments):

Parameter Description Default Vehicle Units
ATC_STR_RAT_IMAX Anti-windup clamp on I-term 1.00 1.0 normalized
ATC_STR_RAT_FLTT Low-pass cutoff on target 0 (off) 0 Hz
ATC_STR_RAT_FLTE Low-pass cutoff on error 10 10 Hz
ATC_STR_RAT_FLTD Low-pass cutoff on derivative 0 (off) 0 Hz
ATC_STR_ACC_MAX Yaw-acceleration limiter on the commanded yaw rate 120 120 deg/s²
ATC_STR_DEC_MAX Yaw deceleration limit; 0 → falls back to ACC_MAX 0 0 deg/s²
ATC_STR_RAT_MAX Hard cap on commanded yaw rate 120 36 deg/s
ATC_TURN_MAX_G Coordinated-turn lateral g cap (only active in higher modes) 0.6 0.6 g
ACRO_TURN_RATE Stick-to-rate scaling at full deflection — 36 deg/s
ATC_STR_ANG_P Outer-loop heading P gain (HOLD/AUTO only; not active in ACRO) 2.0 2.0 —

DataFlash log channels

Channel Description Units
STER_DesTurnRate Yaw-rate setpoint (after input filter) rad/s
STER_TurnRate Measured yaw rate (EKF) rad/s
RCOU_C1 Steering/rudder command sent to actuator PWM
PIDS_Tar PID’s internal target (after rate limiting, when active) rad/s
PIDS_Act PID’s input measurement rad/s
PIDS_Err Target − Act, after error filter rad/s
PIDS_P, _I, _D, _FF Individual PID term outputs normalized
PIDS_DFF, _Dmod, _SRate, _Flags Auxiliary fields —

As with the speed PID, no Out field is logged; total output is P + I + D + FF.

Step-response setup for this lab

Setting Lab value Why
ATC_STR_ACC_MAX 0 Disable rate limiter — let the setpoint be a true step
ATC_STR_RAT_FF 0 for Base FF restored in FeedForward; tuned with PID in Tuned
ATC_STR_RAT_MAX left at 36 deg/s Determines the achievable step amplitude

Restoring normal operation

The lab disables several features (ATC_ACCEL_MAX = 0, ATC_STR_ACC_MAX = 0, ATC_STR_RAT_FF = 0, CRUISE_THROTTLE = 0) only to expose the closed-loop PID dynamics in step-response data. Restore these to their nominal values when the lab is finished: they’re useful in normal operation and required for the autonomous modes used in Lab 3.

Source references

  • ATC parameter reference — companion page with the per-parameter source-code anchors for every ATC_* parameter mentioned above
  • AR_AttitudeControl.cpp — parameter definitions and PID call sites
  • AC_PID.cpp — the underlying PID implementation that all _P, _I, _D, _FF, _FLT*, _IMAX, _SMAX, _PDMX parameters configure
  • Rover ACRO mode docs — official explanation of stick-to-rate mapping
  • Rover speed and steering tuning guide — official tuning recipe (different in tone from a controls-class treatment but useful for cross-reference)

© Brian Bingham · Source on GitHub

 

Built with Quarto