Skip to content

Robot PID auto-tuner · open source

pidtuna

Turns a robot description into tuned joint gains: an analytic start from the model, then measured tuning on the robot.

Point it at a servo or an arm and come back to a proposal: feedback gains, the feed-forward that rides with them, and the before/after on motion the tuner never saw. It never writes a board itself.

A UR5e-class arm in MuJoCo, running in your browser: soft factory gains (left) and pidtuna's result (right) play the same held-out motion. The faint ghost is the commanded pose.

Same motion, before and after

Tracking error (RMS) on held-out motion, simulated, per robot kind. Factory is the drive's as-found gains (deliberately soft defaults); oracle is the best controller a brute-force search finds on the true plant, a ceiling no tuner can know.

Every robot improved at least 19× over its factory gains. Against the oracle the tuner is honest work in progress: within 15 % of its cost on 10 of 33 joints, a median of 33 % above it, and 3× on the lever, where it refused a faster start that saturated the motor. How the oracle is measured →

How it tunes

Five stages, one seam: every motion goes through a Plant you can point at a simulator or a real joint.

  1. 0Analytic start

    From the description alone (inertia, friction, the loop and its sensors): the fastest closed loop that keeps a gain margin of 2 and four other bounds. Moves nothing.

  2. 1Identify

    Short motions, then least squares for inertia, viscous and Coulomb friction and gravity.

  3. 2Sweep

    Raise the bandwidth ×1.2 per rung from the analytic start until a hold rings. Deploy from the last quiet rung, with half its stiffness.

  4. 3Refine

    Try feed-forward terms against damping and bandwidth on the gates: stop error, tracking, ringing, chatter, saturation.

  5. 4Verify

    Play motion no stage has seen. Keep the as-found controller unless the new one wins there.

  6. →Proposal

    Board gains, host feed-forward, the identified model and the before/after, as JSON you review. Nothing is written for you.

The pipeline, with the equations →

Quickstart

The core is pure Python with numpy. MuJoCo arms are an extra.

bash
pip install "pidtuna @ git+https://github.com/zacharyyamaoka/pidtuna"   # once the repository is public
python
from pidtuna import Envelope, Gains, Goal, PlantModel, Servo
from pidtuna.analytic import LoopModel, analytic_controller
from pidtuna.config import proposal
from pidtuna.plants.servo_sim import ServoSim, Truth
from pidtuna.tune import tune

if __name__ == "__main__":  # the simulator plays tapes in a process pool
    # what you know about the servo: its gains now, its travel, its torque cap
    servo = Servo(name="elbow", gains=Gains.from_moteus(100.0, 2.0), torque_limit_nm=3.0,
                  envelope=Envelope(travel_rad=0.5, max_speed_rad_s=3.0, max_torque_nm=3.0, origin_rad=0.0))
    # 0. the analytic start, from the description alone (CAD inertia, datasheet friction, the loop)
    described = PlantModel(inertia_kg_m2=0.005, viscous_nm_s_rad=0.1, coulomb_nm=0.5, gravity_sin_nm=0.3)
    seed, _ = analytic_controller(described, LoopModel(torque_bandwidth_hz=250.0, torque_cap_nm=3.0, travel=0.5))
    # 1-4. identify, sweep, refine, verify, on a simulated joint the tuner never sees inside
    joint = ServoSim(servo, Truth(inertia_kg_m2=0.006, viscous_nm_s_rad=0.12, coulomb_nm=0.6, static_nm=0.8,
                                  gravity_sin_nm=0.3, torque_bandwidth_hz=250.0, velocity_noise_rad_s=0.003))
    result = tune(servo, joint, Goal(stop_allocation_mrad=4.0), seed=seed)
    print(result.before.stop_p90_mrad, "->", result.after.stop_p90_mrad, "mrad stop p90")
    print(proposal(result)["board_set"])   # the moteus keys to set; nothing is written for you
It never writes a board

You get a proposal: the moteus config keys to set, the feed-forward for your host, the evidence. Applying it is your call.

It stays inside a guard

Every gain it tries is held inside a band around what the joint already runs, and the sweep stops at the first hold that rings.

It never leaves a joint worse

Verification is on motion it never chose on. On an arm, all joints move together before anything is delivered.

Read the design decisions, watch the replays, or tune a joint yourself.

Source: coming soon.