Robotics Cheat Sheet

An information dossier for the software side of a desktop robot arm: physics, simulation, C++, testing and measurement. Most formulas are checked numerically against an independent route, and a row with a check says so; claims of fact cite sources, each marked read, listed or derived.

51 formulas · 24 code rules · 157/157 checks pass · MuJoCo 3.17.0 · checked 25 Oct 2026

How to read this

Units are SI throughout, angles in radians unless marked. Each formula states when it holds; outside that, it does not.

One pendulum, all the way through

The physics, simulation and measurement modules use the same compound pendulum: a thin rod on a hinge with a sphere on the end. These numbers are computed from the inputs, not typed.

Rod
20 g · 150 mm long · 4 mm radius
Bob
200 g sphere · 18 mm radius · centre 168 mm below the pivot
Gravity
9.81 m/s² (MuJoCo default)
Timestep
2 ms
II inertia about the pivot
0.0058208 kg·m²
dd pivot to centre of mass
159.55 mm
mgdmgd gravity stiffness
0.34433 N·m/rad
ωn\omega_n natural frequency
7.6912 rad/s
T0T_0 small-angle period
0.81693 s
ℓ\ell equivalent simple-pendulum length
165.83 mm
T(90∘)T(90^\circ) period released from horizontal
0.96425 s
ωnh\omega_n h step size relative to the motion
0.0154

Formula sheet

Grouped by module. For the code modules, short code rules take the place of formulas. Bracketed numbers are sources, listed at the foot of the page.

01

Bench and safety

Module page →
  1. Electrical power

    P=V IP = V\,I
    F1.01[1]
    Symbols
    SymbolMeaningUnit
    PPpowerW
    VVvoltageV
    IIcurrentA
  2. Where a bench supply switches from constant voltage to constant current

    Ideal CV/CC supply with a resistive load. Loads below R_cross put the supply in constant current, and the output voltage falls to I_limit·R.

    Rcross=VsetIlimitR_{\text{cross}} = \dfrac{V_{\text{set}}}{I_{\text{limit}}}
    F1.02✓ 5/5 checked[2][3]
    Symbols and checks
    SymbolMeaningUnit
    RcrossR_{\text{cross}}load resistance at the crossoverΩ
    VsetV_{\text{set}}voltage settingV
    IlimitI_{\text{limit}}current limitA
    • ✓ 20 ohm at 1 V / 0.08 A: predicted CV, Siglent observed CVobserved as stated
    • ✓ 20 ohm: predicted current vs Siglent's measured 0.049 Aexpected 0.05 · got 0.049 · relative error 0.02within 5 %: resistor tolerance and lead resistance
    • ✓ 10 ohm: predicted CC (R below 12.5 ohm), Siglent observed CCobserved as statedSiglent: the current 'stops at just below the current setpoint of 80 mA'
    • ✓ spin-up with winding inductance: the clamp releases at (V - I_lim R)/K (rad/s)expected 70 · got 70.0001 · relative error 1.1×10⁻⁶agrees by construction once the current is steady; the run shows the inductance does not move it. Rotor inertia 1e-05 kg m^2 sets only how long it takes
    • ✓ spin-up: the limit is reached within the first millisecondobserved as statedthe winding current rises with time constant L/R = 0.1 ms
  3. Logic analyser sample rate

    Rule of thumb for digital timing work, not a theorem. Nyquist (2×) is the floor for recovering a band-limited signal, not for resolving edges; more margin resolves timing better.

    fs≥4 fmax⁡f_s \ge 4\,f_{\max}
    F1.03[4]
    Symbols
    SymbolMeaningUnit
    fsf_{s}sample rateHz
    fmaxf_{\text{max}}bandwidth of the fastest signal (for a clocked bus, its clock frequency)Hz
02

Development environment

Module page →
  1. Configure, build and test with presets

    Presets file version 6 (which adds workflow presets) needs CMake 3.25 or later. A preset that inherits another takes every field except name, hidden, inherits, description and displayName, and overrides only what it sets itself; cache variables are merged.

    cmake --preset debug          # configure: Ninja, Debug, sanitizers
    cmake --build --preset debug  # build
    ctest --preset debug          # run the tests
    cmake --workflow --preset ci  # all three, exactly as CI runs them
    F2.01✓ 2/2 checked[5]
    Symbols and checks
    • ✓ cmake --workflow --preset ci: configure, build, test (exit code)expected 0 · got 0 · absolute error 0Debug, AddressSanitizer + UBSan, warnings as errors
    • ✓ ci inherits debug: sanitizers from debug and -Werror of its ownobserved as stated
  2. Give clangd the compile commands

    Makefile and Ninja generators only. Alternatively, point clangd at the folder with a .clangd file (CompileFlags, CompilationDatabase: build/debug).

    # in the base configure preset
    "cacheVariables": { "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" }
    # clangd looks in parent directories and in build/, not build/debug/:
    ln -s build/debug/compile_commands.json .
    F2.02✓ 1/1 checked[6][7][8]
    Symbols and checks
    • ✓ compile_commands.json lists every source fileexpected 9 · got 9 · absolute error 0
  3. Pin a dependency, and keep its warnings out of yours

    SYSTEM needs CMake 3.25 or later. Code that includes the dependency's headers no longer gets warnings from them; your own code still does. The CMake docs advise a commit hash over a tag for servers you do not control, since a tag can be moved; a hash rules out GIT_SHALLOW.

    FetchContent_Declare(mujoco
      GIT_REPOSITORY https://github.com/google-deepmind/mujoco.git
      GIT_TAG        3.17.0   # a release tag; never a branch
      GIT_SHALLOW    TRUE     # needs a tag or branch, not a hash
      SYSTEM)                 # its headers become system headers
    FetchContent_MakeAvailable(mujoco)
    F2.03✓ 2/2 checked[9][10][11]
    Symbols and checks
    • ✓ warnings from the dependency's header, included as SYSTEMexpected 0 · got 0 · absolute error 0
    • ✓ the same header on an ordinary include path warnsobserved as stated
  4. Warnings and sanitizers as a target, linked PRIVATE

    PRIVATE dependencies are used to build the target but are not part of its interface, so consumers do not inherit its compile flags. For a static library, CMake still records PRIVATE dependencies for the final link, so their link options, such as the sanitizer runtime, reach the program that uses the library.

    add_library(arm_project_options INTERFACE)
    target_compile_options(arm_project_options INTERFACE -Wall -Wextra ...)
    target_link_libraries(arm_sim
      PUBLIC  mujoco::mujoco arm::core     # consumers need these too
      PRIVATE arm::project_options)        # only arm_sim's own sources
    F2.04✓ 3/3 checked[12][13][14]
    Symbols and checks
    • ✓ library linking the options PRIVATE compiles with -Wshadowexpected 1 · got 1 · absolute error 0
    • ✓ its consumer compiles without itobserved as stated
    • ✓ the static library's PRIVATE link options reach the consumer's linkobserved as statedthe sanitizer runtime has to be linked into the final program
  5. One locked Python environment per project

    uv run checks that the lockfile matches pyproject.toml and the environment matches the lockfile before every run. Commit uv.lock.

    uv sync                           # create .venv from pyproject.toml and uv.lock
    uv run python scripts/plot.py     # locks and syncs first, then runs
03

Modern C++ for robotics code

Module page →
  1. Own a C object with unique_ptr and its delete function

    The deleter runs once per object owned: when the owner is destroyed, reset or move-assigned over, and never on a null pointer or after release(). The owner cannot be copied.

    using ModelPtr = std::unique_ptr<mjModel, decltype(&mj_deleteModel)>;
    ModelPtr model(mj_loadXML(path, nullptr, err, n), &mj_deleteModel);
    if (!model) throw std::runtime_error(err);
    F3.01✓ 3/3 checked[18][19]
    Symbols and checks
    • ✓ ownership checks ran clean under ASan + UBSan (exit code)expected 0 · got 0 · absolute error 0its static_asserts (move-only, noexcept moves) compiled
    • ✓ objects still alive after the owner's scope endsexpected 0 · got 0 · absolute error 0
    • ✓ deleter calls with a null pointer after a failed loadexpected 0 · got 0 · absolute error 0
  2. Members are destroyed in reverse order of declaration

    Always, whatever order the constructor's initializer list is written in. Bases and members are destroyed in the reverse order of their construction.

    ModelPtr model_;  // declared first: built first, destroyed last
    DataPtr  data_;   // depends on model_: declared second, destroyed first
    F3.02✓ 5/5 checked[20][21]
    Symbols and checks
    • ✓ -Wall warns about an out-of-order initializer list (clang++)observed as statedUbuntu clang version 18.1.3 (1ubuntu1)
    • ✓ list written b, a: built a, b; destroyed b, a (clang++)observed as statedUbuntu clang version 18.1.3 (1ubuntu1)
    • ✓ -Wall warns about an out-of-order initializer list (g++)observed as statedg++ (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
    • ✓ list written b, a: built a, b; destroyed b, a (g++)observed as statedg++ (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
    • ✓ members destroyed in reverse orderobserved as stated
  3. Take ownership in the statement that acquires

    Any exit, including an exception, destroys the owners already built. A raw pointer held at that moment is simply abandoned.

    ModelPtr model(mj_loadXML(...), &mj_deleteModel);  // owned at once
    DataPtr  data(mj_makeData(model.get()), &mj_deleteData);
    if (!data) throw std::runtime_error("mj_makeData failed");  // model is still freed
    F3.03✓ 2/2 checked[19][22]
    Symbols and checks
    • ✓ owned: objects leaked when the second step failsexpected 0 · got 0 · absolute error 0
    • ✓ raw pointers: objects leaked when the second step failsexpected 1 · got 1 · absolute error 0
  4. The rule of zero

    When every member manages itself, write none of the five special members. If you write or delete any one of them, write or delete all five (the rule of five).

    class Model {
      ModelPtr model_;
      DataPtr  data_;
      // no destructor, copy or move written: the members do it all
    };
    static_assert(!std::is_copy_constructible_v<Model>);
    static_assert(std::is_nothrow_move_constructible_v<Model>);
    F3.04✓ 2/2 checked[21][22]
    Symbols and checks
    • ✓ ownership checks ran clean under ASan + UBSan (exit code)expected 0 · got 0 · absolute error 0its static_asserts (move-only, noexcept moves) compiled
    • ✓ after a move, each C object is freed exactly onceobserved as stated
  5. A moved-from unique_ptr is empty

    Guaranteed for unique_ptr. Unless the standard says otherwise, a moved-from standard library object is only in a "valid but unspecified" state, so do not read it before assigning to it.

    auto b = std::move(a);   // b owns the object now
    assert(a == nullptr);    // guaranteed by the standard for unique_ptr
    F3.05✓ 2/2 checked[18][23][24]
    Symbols and checks
    • ✓ a moved-from unique_ptr is nullobserved as stated
    • ✓ the new owner holds the objectobserved as stated
04

Build, test and sanitizers

Module page →
  1. Machine epsilon, double precision

    ε=2−52≈2.22×10−16\varepsilon = 2^{-52} \approx 2.22\times10^{-16}
    F4.01✓ 1/1 checked[25][26]
    Symbols and checks
    SymbolMeaningUnit
    εεgap between 1 and the next doubledimensionless
    • ✓ machine epsilon (numpy) vs 2^-52expected 2.22045×10⁻¹⁶ · got 2.22045×10⁻¹⁶ · absolute error 0
  2. Floating-point comparison with a tolerance

    Choose rtol from the error you expect (round-off grows with the number of operations), and atol for values near zero.

    ∣a−b∣≤max⁡ ⁣(atol, rtol⋅max⁡(∣a∣,∣b∣))|a-b| \le \max\!\big(\text{atol},\ \text{rtol}\cdot\max(|a|,|b|)\big)
    Symbols
    SymbolMeaningUnit
    atolatolabsolute toleranceunits of a
    rtolrtolrelative tolerancedimensionless
  3. EXPECT carries on, ASSERT returns

    A failed ASSERT returns from the current function only, so code after it in that function does not run (including clean-up written there).

    ASSERT_NE(model, nullptr);       // fatal: no point continuing without it
    EXPECT_EQ(model->nv, 1);         // non-fatal: report, keep checking
    EXPECT_GT(model->opt.timestep, 0.0);
    F4.03✓ 2/2 checked[29]
    Symbols and checks
    • ✓ code after a failed EXPECT still runsobserved as stated
    • ✓ code after a failed ASSERT does not runobserved as stated
  4. Comparing doubles in GoogleTest

    Four ULPs is between about 4×10⁻¹⁶ and 9×10⁻¹⁶ relative, so only round-off passes. Compared with exactly zero it passes nothing but the smallest subnormal numbers, so near zero use EXPECT_NEAR, with a bound from the error you expect (F4.02).

    EXPECT_DOUBLE_EQ(a, b);        // within 4 ULPs: scales with the numbers
    EXPECT_NEAR(a, b, abs_error);  // within an absolute bound you choose
    F4.04✓ 5/5 checked[28]
    Symbols and checks
    • ✓ EXPECT_DOUBLE_EQ accepts 4 ULPsobserved as stated
    • ✓ EXPECT_DOUBLE_EQ rejects 5 ULPsobserved as stated
    • ✓ 4 ULPs at 1e9 is 4.8e-7 in absolute termsexpected 4.76837×10⁻⁷ · got 4.768×10⁻⁷ · relative error 7.8×10⁻⁵the tolerance scales with the size of the numbers
    • ✓ EXPECT_DOUBLE_EQ(0, 1e-20) failsobserved as stated
    • ✓ EXPECT_NEAR(0, 1e-20, 1e-12) passesobserved as stated
  5. The sanitizer flags, and why each one is there

    Use the same flags when linking. AddressSanitizer typically slows a program by about 2×. Without -fno-sanitize-recover, most UBSan checks print a report and carry on, and the exit code says nothing went wrong.

    -fsanitize=address,undefined      # memory errors; undefined behaviour
    -fno-sanitize-recover=undefined   # stop at the first UB, so tests fail
    -fno-omit-frame-pointer           # readable stack traces
    F4.05✓ 4/4 checked[30][31]
    Symbols and checks
    • ✓ use-after-free: ASan stops the programobserved as stated
    • ✓ signed overflow with -fno-sanitize-recover: stopsobserved as stated
    • ✓ same bug, default recovery: reported, but exit code 0observed as stateda test runner reading the exit code would call this a pass
    • ✓ control: the same program without the bug runs clean (exit code)expected 0 · got 0 · absolute error 0
  6. Switching a check off silences real bugs too

    The documented false positive (the wiki knows of at least one kind) comes from mixing code built with and without AddressSanitizer. Even then, prefer building everything with it; failing that, confine the option to the affected binary and write down why.

    ASAN_OPTIONS=detect_container_overflow=0 ./container_overflow   # reports nothing, exits 0
    F4.06✓ 2/2 checked[32]
    Symbols and checks
    • ✓ real read past size(): reportedobserved as statedlibc++ std::vector
    • ✓ with detect_container_overflow=0: silent, exit 0observed as statedthe bug is still there; only the report is gone
  7. A test must be able to fail

    Watch each new test fail once, against missing or deliberately broken code, before trusting its pass. Take expected values from an independent route, never from the code being tested.

    // copied from the code under test: agrees with it, bug and all
    EXPECT_NEAR(to_radians(30), 30 * pi / kHalfTurnDegrees, 1e-12);
    // from somewhere else: sin 30 degrees is one half
    EXPECT_NEAR(std::sin(to_radians(30)), 0.5, 1e-12);
    F4.07✓ 4/4 checked[33][34]
    Symbols and checks
    • ✓ as written: the test fails, on the limit and on the massobserved as stated
    • ✓ correct code: tests failingexpected 0 · got 0 · absolute error 0
    • ✓ bug planted: independent expected value failsobserved as stated
    • ✓ bug planted: expected value copied from the code still passesobserved as stated
  8. When test discovery runs

    POST_BUILD (the default) lists the tests as part of the build, so a test binary that cannot start breaks the build. PRE_TEST lists them when ctest starts, where the binary's run-time dependencies are more likely to be found; a binary that cannot start then stops ctest before any test runs.

    gtest_discover_tests(arm_tests DISCOVERY_MODE PRE_TEST)
    F4.08✓ 3/3 checked[35]
    Symbols and checks
    • ✓ POST_BUILD: a test binary that cannot start breaks the buildobserved as stated
    • ✓ PRE_TEST: the build succeeds (exit code)expected 0 · got 0 · absolute error 0
    • ✓ PRE_TEST: ctest stops at discovery and runs no testsobserved as statedthe healthy test in the same project does not run either
05

MuJoCo essentials

Module page →
  1. MuJoCo potential energy (gravity part)

    Zero is where the centre of mass lies on the horizontal plane through the world origin, not the bottom of the swing. Passive springs (joint, tendon, flex) add their stored energy; constraint energy is not included.

    VMuJoCo=−∑bmb g⋅xbV_{\text{MuJoCo}} = -\sum_b m_b\, \mathbf{g}\cdot\mathbf{x}_b
    F5.01✓ 1/1 checked[36][37]
    Symbols and checks
    SymbolMeaningUnit
    mbm_{b}mass of body bkg
    gggravity vector (default 0 0 −9.81)m/s²
    xbx_{b}centre of mass of body bm
    • ✓ MuJoCo PE + m g d vs hand PE (worst, J)expected 0 · got 7.63278×10⁻¹⁷ · absolute error 7.6×10⁻¹⁷MuJoCo's zero height is the pivot; the constant offset is m g d
  2. MuJoCo kinetic energy

    T=12 vTM(q) vT = \tfrac12\,\mathbf{v}^{\mathsf T} M(\mathbf{q})\,\mathbf{v}
    F5.02✓ 1/1 checked[36][38][39]
    Symbols and checks
    SymbolMeaningUnit
    vvgeneralised velocityrad/s or m/s
    MMmass matrixkg·m² or kg
    • ✓ MuJoCo KE vs 1/2 I thetadot^2 (worst, J)expected 0 · got 5.55112×10⁻¹⁷ · absolute error 5.6×10⁻¹⁷
  3. Reflected (armature) inertia through a gear

    Direct drive is N = 1, so the rotor's own inertia adds to the joint. Enter it either as the joint's armature (the reflected value) or as the actuator's armature (the rotor's own, which MuJoCo scales by the actuator's gear squared, so only when gear is the mechanical ratio), not both, or it is counted twice.

    Ireflected=N2 IrotorI_{\text{reflected}} = N^2\, I_{\text{rotor}}
    F5.03✓ 3/3 checked[36][38]
    Symbols and checks
    SymbolMeaningUnit
    NNgear ratio (motor turns per joint turn)dimensionless
    IrotorI_{\text{rotor}}rotor inertiakg·m²
    • ✓ joint armature 1e-4: mass matrix = I + 1e-4 (kg m^2)expected 0.0059208 · got 0.0059208 · relative error 1.5×10⁻¹⁶
    • ✓ actuator armature 1e-6 at gear 10: mass matrix = I + 10^2 x 1e-6expected 0.0059208 · got 0.0059208 · relative error 1.5×10⁻¹⁶the rotor's own inertia, reflected by the actuator's gear
    • ✓ both set: the two add (counted twice if they describe one rotor)expected 0.0060208 · got 0.0060208 · relative error 1.4×10⁻¹⁶
  4. Constraint time constant floor

    The docs say timeconst should be at least 2h. In the standard (timeconst, dampratio) format, MuJoCo raises a smaller value to 2h unless the refsafe flag is disabled; the discrete integrator applies a different safeguard instead.

    timeconst≥2h\text{timeconst} \ge 2h
    Symbols
    SymbolMeaningUnit
    timeconsttimeconstsolref time constants
    hhtimesteps
  5. The simulation loop

    mj_forward computes everything for the current state without advancing time. Splitting a step into mj_step1 and mj_step2 reproduces mj_step only with the single-step integrators (Euler, implicit, implicitfast, discrete). With RK4, mj_step2 quietly integrates with Euler; set controls in a callback instead.

    while (d->time < t_end) {
      mj_step(m, d);     // forward dynamics at d->time, then integrate one step
    }
    // controls that need this step's intermediate results (single-step integrators only):
    mj_step1(m, d);  /* set d->ctrl */  mj_step2(m, d);
    F5.05✓ 4/4 checked[42]
    Symbols and checks
    • ✓ mj_step vs mj_step1 + mj_step2, 500 steps, Euler, implicit, implicitfast, discrete (largest gap, rad)expected 0 · got 0 · absolute error 0
    • ✓ RK4: mj_step1 + mj_step2 differs from mj_stepobserved as statedmj_step2 integrates with Euler when the model uses RK4
    • ✓ mj_forward leaves the time unchanged (s)expected 0 · got 0 · absolute error 0
    • ✓ the sheet's C++ statements compile (-Wconversion -Wsign-conversion -Werror)expected 0 · got 0 · absolute error 0F5.05, F5.06, F5.10, F5.11, F5.12; F5.07 lists fields rather than statements
  6. Energy is off by default, and with Euler one step behind

    With the single-step integrators (Euler, implicit, implicitfast, discrete), energy is computed inside forward dynamics, before the integrator moves the state on. With RK4 it comes from the last intermediate stage, close to the new state but not exactly it. An energy sensor in the model also turns the computation on. Potential energy covers gravity and passive springs; constraint energy is not included.

    // in the model: <option><flag energy="enable"/></option>
    mj_step(m, d);     // single-step integrators: d->energy describes the state at the start of this step
    mj_forward(m, d);  // recompute: d->energy now describes the state you hold
    F5.06✓ 6/6 checked[36][42][43]
    Symbols and checks
    • ✓ energy flag off (default): energy stays zero (J)expected 0 · got 0 · absolute error 0
    • ✓ after mj_step, energy equals the pre-step state's: Euler, implicit, implicitfast, discrete (largest gap, J)expected 0 · got 0 · absolute error 0
    • ✓ and differs from the post-step state'sobserved as statedcall mj_forward after mj_step to get the energy of the new state
    • ✓ RK4: energy after mj_step equals the energy at its last intermediate state (J)expected 0 · got 0 · absolute error 0gap to the old state 5.7e-04 J, to the new state 6.2e-09 J; the docs say energy is computed once per RK4 step
    • ✓ flag off, but an energy sensor in the model: energy is computedobserved as stated
    • ✓ the sheet's C++ statements compile (-Wconversion -Wsign-conversion -Werror)expected 0 · got 0 · absolute error 0F5.05, F5.06, F5.10, F5.11, F5.12; F5.07 lists fields rather than statements
  7. Positions and velocities can differ in size

    Rotations are stored as unit quaternions (four numbers) but move with three angular velocities, so nq ≥ nv. Index qpos with jnt_qposadr and qvel with jnt_dofadr, never with the same index.

    m->nq  // dim(qpos): hinge 1, slide 1, ball 4, free 7 (position + unit quaternion)
    m->nv  // dim(qvel): hinge 1, slide 1, ball 3, free 6
    F5.07✓ 3/3 checked[36][44]
    Symbols and checks
    • ✓ hinge: nq = nv = 1observed as stated
    • ✓ free joint: nq = 7, nv = 6observed as statedposition plus unit quaternion; three linear plus three angular velocities
    • ✓ ball joint: nq = 4, nv = 3observed as stated
  8. MJCF angles are degrees unless you say otherwise

    The default for MJCF is degree (URDF is always radian). The compiler converts to radians, and mjModel and mjData always hold radians. A range written in radians under the default is read as degrees, silently.

    <compiler angle="radian"/>  <!-- or write every angle attribute in degrees -->
    F5.08✓ 5/5 checked[36]
    Symbols and checks
    • ✓ range="-90 90" with the default compiler: stored upper limit (rad)expected 1.5708 · got 1.5708 · relative error 0
    • ✓ the same with angle="radian": stored upper limit (rad)expected 90 · got 90 · absolute error 0read as 90 radians: no error, a wrong model
    • ✓ as written: 1.5708 read as degrees, stored upper limit (rad)expected 0.0274156 · got 0.0274156 · relative error 0the joint is limited (autolimits) to about 1.57 degrees
    • ✓ as written: the joint is limitedobserved as stated
    • ✓ fixed (angle="radian"): stored upper limit (rad)expected 1.5708 · got 1.5708 · relative error 0
  9. Mass and inertia come from the geoms unless you give them

    With inertiafromgeom="auto" (the default), a body without an inertial element gets its mass and inertia from its geoms, each geom from its mass or, failing that, its volume times density (default 1000). Units are whatever you use consistently; the defaults assume metres, kilograms and seconds.

    <geom type="sphere" size="0.018" mass="0.2"/>   <!-- explicit: use this -->
    <geom type="sphere" size="0.018"/>              <!-- density 1000: water -->
    F5.09✓ 3/3 checked[36][45]
    Symbols and checks
    • ✓ sphere with no mass: body mass = 1000 x volume (kg)expected 0.024429 · got 0.024429 · relative error 1.4×10⁻¹⁶the running example's 18 mm bob would weigh this, not 200 g
    • ✓ as written: link mass from density 1000 (kg)expected 0.024429 · got 0.024429 · relative error 1.4×10⁻¹⁶
    • ✓ fixed (mass on the geom): link mass (kg)expected 0.2 · got 0.2 · relative error 0
  10. Same state, same step, same result

    The integration state is everything the next step reads. It includes time, positions, velocities, actuator activations, history buffers and plugin state; the user inputs (controls, applied forces, equality-constraint toggles, mocap poses, userdata); and the solver warm start. Restore all of it and the result is bit-for-bit identical within one MuJoCo version on the same architecture; restore less, and small differences can grow during integration, quickly in models with contact.

    std::vector<mjtNum> s(static_cast<std::size_t>(mj_stateSize(m, mjSTATE_INTEGRATION)));
    mj_getState(m, d, s.data(), mjSTATE_INTEGRATION);  // save everything the next step reads
    // ... later ...
    mj_setState(m, d, s.data(), mjSTATE_INTEGRATION);  // restore: the next mj_step is identical
    F5.10✓ 3/3 checked[42][46]
    Symbols and checks
    • ✓ two runs of 2000 steps: bit-identical stateobserved as stated
    • ✓ save the integration state, run, restore, rerun: bit-identicalobserved as stated
    • ✓ the sheet's C++ statements compile (-Wconversion -Wsign-conversion -Werror)expected 0 · got 0 · absolute error 0F5.05, F5.06, F5.10, F5.11, F5.12; F5.07 lists fields rather than statements
  11. Read back what the compiler stored

    The text lists each array under its mjModel name (jnt_range, body_mass, body_inertia, ...), so search for the field you meant to set. mj_printModel does the same with a fixed format of two significant figures ("% -9.2g"); mj_printData prints mjData. Slide-joint limits are lengths, not angles.

    mj_printFormattedModel(m, "model.txt", "%.6g");  // every field of mjModel, after compilation
    // or read one field directly: m->jnt_range[2 * j + 1] is joint j's upper limit (radians for a hinge)
    F5.11✓ 9/9 checked[44][45][47][48]
    Symbols and checks
    • ✓ the page's geom is the running example's bob (radius, depth)observed as stated
    • ✓ as written: 1.5708 read as degrees, stored upper limit (rad)expected 0.0274156 · got 0.0274156 · relative error 0the joint is limited (autolimits) to about 1.57 degrees
    • ✓ as written: link mass from density 1000 (kg)expected 0.024429 · got 0.024429 · relative error 1.4×10⁻¹⁶
    • ✓ mj_printFormattedModel shows jnt_range and body_mass as storedobserved as statedprinted with %.6g, so agreeing to six figures
    • ✓ the page's test compiles against libmujoco 3.17.0 (-Wall -Wextra -Wconversion -Werror)expected 0 · got 0 · absolute error 0
    • ✓ the sheet's C++ statements compile (-Wconversion -Wsign-conversion -Werror)expected 0 · got 0 · absolute error 0F5.05, F5.06, F5.10, F5.11, F5.12; F5.07 lists fields rather than statements
    • ✓ as written: the test fails, on the limit and on the massobserved as stated
    • ✓ C++ reads the same stored limit as Python (rad)expected 0.0274156 · got 0.0274156 · relative error 0gtest prints the value it found
    • ✓ fixed: the test passes (exit code)expected 0 · got 0 · absolute error 0
  12. What the loader's return value means

    Observed with MuJoCo 3.17.0. The Programming chapter says the loaders return null on an error or a warning; for a compiler warning, mj_loadXML in fact returns the model and leaves the warning in the buffer. Check the buffer as well as the pointer. ModelPtr is module 03's owning pointer.

    std::array<char, 1000> msg{};
    ModelPtr m(mj_loadXML(path, nullptr, msg.data(), static_cast<int>(msg.size())), &mj_deleteModel);
    if (!m) { /* the model failed to load; msg says why */ }
    else if (msg[0] != '\0') { /* it loaded, with a compiler warning in msg */ }
    F5.12✓ 6/6 checked[42][49]
    Symbols and checks
    • ✓ the sheet's C++ statements compile (-Wconversion -Wsign-conversion -Werror)expected 0 · got 0 · absolute error 0F5.05, F5.06, F5.10, F5.11, F5.12; F5.07 lists fields rather than statements
    • ✓ clean model: pointer returned, message emptyobserved as stated
    • ✓ compiler warning: pointer still returned, warning in the messageobserved as statedthe Programming chapter says null on an error or a warning; for this warning, it is not null
    • ✓ error: null pointer, reason in the messageobserved as stated
    • ✓ as written: it loads with an empty message, so no compiler warning eitherobserved as statedthe test's EXPECT_STREQ on the message buffer passes
    • ✓ fixed model plus a compiler warning: the test fails, on the message aloneobserved as statedso the empty-message check can fail
06

Pendulum physics

Module page →
  1. Solid cylinder about a transverse axis through its centre

    Ic=112 m (3r2+L2)I_c = \tfrac{1}{12}\, m\,(3r^2 + L^2)
    F6.01✓ 1/1 checked[50][51]
    Symbols and checks
    SymbolMeaningUnit
    mmmasskg
    rrradiusm
    LLlengthm
    • ✓ I about pivot: hand formulas vs MuJoCo mass matrixexpected 0.0058208 · got 0.0058208 · relative error 1.5×10⁻¹⁶
  2. Parallel-axis theorem

    The two axes must be parallel, and one must pass through the centre of mass.

    I=Icm+m s2I = I_{\text{cm}} + m\,s^2
    F6.02✓ 1/1 checked[52]
    Symbols and checks
    SymbolMeaningUnit
    IcmI_{\text{cm}}inertia about the parallel axis through the centre of masskg·m²
    ssdistance between the axesm
    • ✓ I about pivot: hand formulas vs MuJoCo mass matrixexpected 0.0058208 · got 0.0058208 · relative error 1.5×10⁻¹⁶
  3. Rod hanging from one end, about the pivot

    Solid cylinder, pivot on the end face's centre, axis perpendicular to the rod.

    Irod=mr(L23+r24)I_{\text{rod}} = m_r\Big(\dfrac{L^2}{3} + \dfrac{r^2}{4}\Big)
    F6.03✓ 1/1 checked[50][52]
    Symbols and checks
    SymbolMeaningUnit
    mrm_{r}rod masskg
    LLrod lengthm
    rrrod radiusm
    • ✓ I about pivot: hand formulas vs MuJoCo mass matrixexpected 0.0058208 · got 0.0058208 · relative error 1.5×10⁻¹⁶
  4. Solid sphere about a pivot at distance D

    Ibob=25 mbR2+mbD2I_{\text{bob}} = \tfrac25\, m_b R^2 + m_b D^2
    F6.04✓ 1/1 checked[50][51][52]
    Symbols and checks
    SymbolMeaningUnit
    mbm_{b}sphere masskg
    RRsphere radiusm
    DDpivot to sphere centrem
    • ✓ I about pivot: hand formulas vs MuJoCo mass matrixexpected 0.0058208 · got 0.0058208 · relative error 1.5×10⁻¹⁶
  5. Centre-of-mass distance from the pivot

    d=∑imisi∑imid = \dfrac{\sum_i m_i s_i}{\sum_i m_i}
    F6.05✓ 1/1 checked[53]
    Symbols and checks
    SymbolMeaningUnit
    mim_{i}part masskg
    sis_{i}pivot to part's centre of massm
    • ✓ centre-of-mass depth vs MuJoCo xiposexpected 0.159545 · got 0.159545 · relative error 0
  6. Equation of motion, compound pendulum

    Rigid body, frictionless pivot, no drive torque.

    I θ¨+mgdsin⁡θ=0I\,\ddot\theta + m g d \sin\theta = 0
    F6.06✓ 1/1 checked[38][54]
    Symbols and checks
    SymbolMeaningUnit
    IIinertia about the pivotkg·m²
    mmtotal masskg
    gggravitym/s²
    ddpivot to centre of massm
    θθangle from hangingrad
    • ✓ T0 vs MuJoCo RK4 period at 0.5 degexpected 0.816927 · got 0.816931 · relative error 4.8×10⁻⁶0.5 deg amplitude adds about 5e-6 to the period
  7. Natural frequency and small-angle period

    Small angles (sin θ ≈ θ). At 5° the true period is 0.05 % longer.

    ωn=mgdI,T0=2πImgd\omega_n = \sqrt{\dfrac{m g d}{I}},\qquad T_0 = 2\pi\sqrt{\dfrac{I}{m g d}}
    F6.07✓ 2/2 checked[54]
    Symbols and checks
    SymbolMeaningUnit
    ωnω_{n}natural angular frequencyrad/s
    T0T_{0}small-angle periods
    • ✓ T0 vs MuJoCo RK4 period at 0.5 degexpected 0.816927 · got 0.816931 · relative error 4.8×10⁻⁶0.5 deg amplitude adds about 5e-6 to the period
    • ✓ period excess at 5 deg (fraction)expected 4.75965×10⁻⁴ · got 4.76172×10⁻⁴ · relative error 4.4×10⁻⁴the '0.05 % at 5 deg' claim
  8. Equivalent simple-pendulum length

    ℓ=Imd\ell = \dfrac{I}{m d}
    F6.08✓ 1/1 checked[54]
    Symbols and checks
    SymbolMeaningUnit
    ℓℓlength of the simple pendulum with the same periodm
    • ✓ simple pendulum at ell gives T0expected 0.816927 · got 0.816927 · relative error 0
  9. Period at large amplitude

    Undamped. The series converges slowly past about 60°; use the elliptic form there.

    T=2π T0 K ⁣(sin⁡θ02)≈T0(1+θ0216+11 θ043072+⋯)T = \dfrac{2}{\pi}\,T_0\,K\!\big(\sin\tfrac{\theta_0}{2}\big) \approx T_0\Big(1 + \dfrac{\theta_0^2}{16} + \dfrac{11\,\theta_0^4}{3072} + \cdots\Big)
    F6.09✓ 3/3 checked[55][56]
    Symbols and checks
    SymbolMeaningUnit
    θ0θ_{0}release amplituderad
    KKcomplete elliptic integral of the first kind, at modulus sin(θ₀/2)dimensionless
    • ✓ elliptic period at 90 deg vs MuJoCo RK4expected 0.964252 · got 0.964252 · relative error 9.2×10⁻¹⁵
    • ✓ two-term series at 90 deg vs ellipticexpected 0.964252 · got 0.960716 · relative error 0.0037series truncation error at 90 deg is about 0.4 %
    • ✓ period excess at 5 deg (fraction)expected 4.75965×10⁻⁴ · got 4.76172×10⁻⁴ · relative error 4.4×10⁻⁴the '0.05 % at 5 deg' claim
  10. Total mechanical energy

    Potential energy is zero at the bottom of the swing; MuJoCo's is zero at the pivot height, so the two differ by the constant m·g·d.

    E=12Iθ˙2+mgd (1−cos⁡θ)E = \tfrac12 I\dot\theta^2 + m g d\,(1-\cos\theta)
    F6.10✓ 2/2 checked[37][39][54]
    Symbols and checks
    SymbolMeaningUnit
    EEenergyJ
    θ˙θ̇angular velocityrad/s
    • ✓ MuJoCo PE + m g d vs hand PE (worst, J)expected 0 · got 7.63278×10⁻¹⁷ · absolute error 7.6×10⁻¹⁷MuJoCo's zero height is the pivot; the constant offset is m g d
    • ✓ MuJoCo KE vs 1/2 I thetadot^2 (worst, J)expected 0 · got 5.55112×10⁻¹⁷ · absolute error 5.6×10⁻¹⁷
  11. Peak angular speed from release angle

    Undamped, released from rest.

    θ˙max⁡=2mgd (1−cos⁡θ0)I\dot\theta_{\max} = \sqrt{\dfrac{2 m g d\,(1-\cos\theta_0)}{I}}
    F6.11✓ 1/1 checked[54]
    Symbols and checks
    SymbolMeaningUnit
    θ˙maxθ̇_{\text{max}}angular speed at the bottomrad/s
    • ✓ peak speed from 90 deg vs MuJoCo RK4expected 10.8771 · got 10.8771 · relative error 3.6×10⁻¹¹
  12. Where added mass slows the swing

    A point mass added below the pivot, on the vertical through the pivot and the centre of mass. Farther down than ℓ it slows the swing, higher up it speeds it up, and exactly at ℓ (the centre of oscillation) it changes nothing, whatever its size. Above the pivot (s < 0) the rule does not hold.

    ℓ′=I+δm s2md+δm s,ℓ′>ℓ  ⟺  s>ℓ\ell' = \dfrac{I + \delta m\, s^2}{m d + \delta m\, s},\qquad \ell' > \ell \iff s > \ell
    F6.12✓ 3/3 checked[54][57]
    Symbols and checks
    SymbolMeaningUnit
    δmδmadded point masskg
    ssdepth of the added mass below the pivot (s > 0)m
    • ✓ 5 g added at s = ell: period change (fraction)expected 0 · got 1.67833×10⁻⁷ · absolute error 1.7×10⁻⁷nonzero only through the 1 mm sphere's own inertia
    • ✓ 5 g at s = ell/2 shortens the periodobserved as stated
    • ✓ 5 g at s = 1.5 ell lengthens the periodobserved as stated
07

Numerical integration

Module page →
  1. Explicit (forward) Euler

    Not offered by MuJoCo; included because it is the textbook baseline.

    vt+h=vt+h at,qt+h=qt+h vtv_{t+h} = v_t + h\,a_t,\qquad q_{t+h} = q_t + h\,v_t
    F7.01✓ 2/2 checked[46]
    Symbols and checks
    SymbolMeaningUnit
    hhtimesteps
    aaaccelerationrad/s²
    • ✓ the page's two update loops compile (-Wall -Wextra -Wconversion -Werror)expected 0 · got 0 · absolute error 0
    • ✓ C++ explicit loop: energy ratio after 20 s, vs the Python runexpected 10.5334 · got 10.5334 · relative error 0
  2. Semi-implicit Euler, MuJoCo's default

    Position is updated with the new velocity. Symplectic when the mass matrix is constant (a single hinge, as in the running example); in multi-link models the mass matrix depends on the pose, MuJoCo's Euler is not symplectic, and the energy can drift either way. MuJoCo also treats joint damping implicitly unless the eulerdamp flag is disabled.

    vt+h=vt+h at,qt+h=qt+h vt+hv_{t+h} = v_t + h\,a_t,\qquad q_{t+h} = q_t + h\,v_{t+h}
    F7.02✓ 8/8 checked[36][46][58][59]
    Symbols and checks
    • ✓ modified energy drift over 1e5 steps (relative)expected 0 · got 4.20402×10⁻¹⁴ · absolute error 4.2×10⁻¹⁴
    • ✓ straight from 60 deg, Euler at 2 ms: the 2 s window means rise steadily (a drift, not a band)observed as stated9 of 9 successive windows higher; first +0.014, last +0.409 m g L
    • ✓ straight from 60 deg: halving the step at least halves the gain in 20 s, twice overobserved as stated+0.450, +0.177, +0.079 m g L at 2, 1, 0.5 ms
    • ✓ elbow bent 90 deg, 2 s: Euler loses energy, and each halved step about halves the lossobserved as stated-0.0435, -0.0238, -0.0125 m g L at 2, 1, 0.5 ms
    • ✓ straight from 60 deg under RK4 at 2 ms: change below 1e-6 m g Lobserved as statedchange -1.2e-08 m g L
    • ✓ semi-implicit loop coded by hand vs MuJoCo Euler after 20 s (rad)expected 0 · got 4.44089×10⁻¹⁶ · absolute error 4.4×10⁻¹⁶
    • ✓ the page's two update loops compile (-Wall -Wextra -Wconversion -Werror)expected 0 · got 0 · absolute error 0
    • ✓ C++ semi-implicit loop vs MuJoCo Euler after 20 s (rad)expected 0 · got 4.44089×10⁻¹⁶ · absolute error 4.4×10⁻¹⁶
  3. Implicit-in-velocity update (MuJoCo implicit, implicitfast)

    With no velocity-dependent forces (D = 0) this reduces to semi-implicit Euler. implicitfast drops the Coriolis and centripetal terms from D. In both, D leaves out the constraint forces J^T f, as MuJoCo's documentation states.

    (M+hD) vt+h=(M+hD) vt+h Ma(vt),D≡−∂∂v(τ−c)(M + hD)\,v_{t+h} = (M+hD)\,v_t + h\,M a(v_t),\qquad D \equiv -\dfrac{\partial}{\partial v}\big(\tau - c\big)
    F7.03✓ 3/3 checked[46]
    Symbols and checks
    SymbolMeaningUnit
    DDvelocity derivative of the forces (damping-like)N·m·s/rad
    • ✓ undamped: max |q_Euler - q_implicitfast| (rad)expected 0 · got 0 · absolute error 0
    • ✓ joint damping only: max difference (rad)expected 0 · got 0 · absolute error 0Euler already treats joint damping implicitly
    • ✓ undamped: max |q_Euler - q_implicit| (rad)expected 0 · got 5.55112×10⁻¹⁶ · absolute error 5.6×10⁻¹⁶
  4. Classical fourth-order Runge–Kutta (RK4)

    Four force evaluations per step, so about four times the cost per step of Euler (MuJoCo docs, timestep).

    k1=f(yt), k2=f(yt+h2k1), k3=f(yt+h2k2), k4=f(yt+hk3),yt+h=yt+h6 (k1+2k2+2k3+k4)k_1 = f(y_t),\ k_2 = f\big(y_t+\tfrac h2 k_1\big),\ k_3 = f\big(y_t+\tfrac h2 k_2\big),\ k_4 = f(y_t+h k_3),\quad y_{t+h} = y_t + \tfrac h6\,(k_1 + 2k_2 + 2k_3 + k_4)
    F7.04✓ 1/1 checked[36][60]
    Symbols and checks
    • ✓ same cost (RK4 at 2 ms, Euler at 0.5 ms): RK4's energy error is smallerobserved as statedRK4 1.8e-09, Euler 1.9e-03
  5. Order of accuracy and what halving h buys

    Asymptotic: h small enough, and the solution smooth.

    e(h)≈C hp ⇒ e(h)e(h/2)≈2p,pmeasured=log⁡2 ⁣e(h)e(h/2)e(h) \approx C\,h^{p}\ \Rightarrow\ \dfrac{e(h)}{e(h/2)} \approx 2^{p},\qquad p_{\text{measured}} = \log_2\!\dfrac{e(h)}{e(h/2)}
    F7.05✓ 9/9 checked[60][61]
    Symbols and checks
    SymbolMeaningUnit
    eeglobal error at a fixed end timeunits of the quantity
    pporder (1 for Euler and 4 for RK4)dimensionless
    • ✓ measured order, MuJoCo Eulerexpected 1 · got 1.01198 · relative error 0.012
    • ✓ measured order, MuJoCo RK4expected 4 · got 4.02344 · relative error 0.0059
    • ✓ Euler order from differences of three runs, no referenceexpected 1 · got 1.03436 · relative error 0.034
    • ✓ straight from 60 deg: halving the step at least halves the gain in 20 s, twice overobserved as stated+0.450, +0.177, +0.079 m g L at 2, 1, 0.5 ms
    • ✓ elbow bent 90 deg, 2 s: Euler loses energy, and each halved step about halves the lossobserved as stated-0.0435, -0.0238, -0.0125 m g L at 2, 1, 0.5 ms
    • ✓ the same release over 20 s: halving the step from 2 to 1 ms does not shrink the lossobserved as stated-0.0821 then -0.1219 m g L: the runs have parted ways
    • ✓ explicit Euler: halving h halves the log of the growthexpected 2 · got 1.99473 · relative error 0.0026
    • ✓ MuJoCo Euler: halving h halves the excursionexpected 2 · got 2.00774 · relative error 0.0039
    • ✓ RK4: halving h cuts the loss by 2^5expected 32 · got 32.0025 · relative error 8×10⁻⁵per step (wh)^6, and twice as many steps
  6. What semi-implicit Euler conserves (linear oscillator)

    Exact for q̈ = −ω²q with the update in F7.02. True energy oscillates around it; at turning points (v = 0) the two agree.

    H~=v2+ω2q2−h ω2q v=const\tilde H = v^2 + \omega^2 q^2 - h\,\omega^2 q\,v = \text{const}
    F7.06✓ 1/1 checked[58][62]
    Symbols and checks
    SymbolMeaningUnit
    ωωoscillator angular frequencyrad/s
    qqpositionrad
    vvvelocityrad/s
    • ✓ modified energy drift over 1e5 steps (relative)expected 0 · got 4.20402×10⁻¹⁴ · absolute error 4.2×10⁻¹⁴
  7. Energy wobble of semi-implicit Euler

    Linear oscillator, ωh ≪ 1; a nonlinear pendulum at large amplitude wobbles somewhat less.

    ΔEE≈±ωh2at twice the swing frequency, no trend\dfrac{\Delta E}{E} \approx \pm\dfrac{\omega h}{2}\quad\text{at twice the swing frequency, no trend}
    F7.07✓ 5/5 checked[58][62]
    Symbols and checks
    • ✓ Euler energy wobble amplitude at 5 degexpected 0.00769125 · got 0.0076876 · relative error 4.7×10⁻⁴
    • ✓ no trend: mean of last 10 % minus first 10 %expected 0 · got 5.21858×10⁻⁵ · absolute error 5.2×10⁻⁵
    • ✓ MuJoCo Euler, 5 deg, 2 ms: largest energy excursion vs wh/2expected 0.00769125 · got 0.0077471 · relative error 0.0073
    • ✓ MuJoCo Euler: halving h halves the excursionexpected 2 · got 2.00774 · relative error 0.0039
    • ✓ from 30 deg, MuJoCo Euler's largest excursion vs wh/2expected 0.00769125 · got 0.00761843 · relative error 0.0095
  8. Frequency error of semi-implicit Euler

    Linear oscillator.

    cos⁡(ω~h)=1−(ωh)22 ⇒ ω~≈ω(1+(ωh)224)\cos(\tilde\omega h) = 1 - \dfrac{(\omega h)^2}{2}\ \Rightarrow\ \tilde\omega \approx \omega\Big(1 + \dfrac{(\omega h)^2}{24}\Big)
    F7.08✓ 2/2 checked[62]
    Symbols and checks
    • ✓ numerical frequency, exact vs seriesexpected 7.69132 · got 7.69132 · relative error 2.6×10⁻¹⁰
    • ✓ measured frequency of the recursionexpected 7.69132 · got 7.69132 · relative error 2.9×10⁻¹¹
  9. Explicit Euler pumps energy in

    Linear oscillator: energy grows every step, for any h.

    En+1En=1+(ωh)2\dfrac{E_{n+1}}{E_n} = 1 + (\omega h)^2
    F7.09✓ 6/6 checked[63]
    Symbols and checks
    • ✓ explicit Euler energy ratio per stepexpected 1.00024 · got 1.00024 · relative error 0
    • ✓ explicit Euler, 5 deg, 20 s at 2 ms: energy ratio vs (1 + (wh)^2)^nexpected 10.654 · got 10.5334 · relative error 0.011small-swing prediction; the pendulum is slightly softer
    • ✓ explicit Euler: halving h halves the log of the growthexpected 2 · got 1.99473 · relative error 0.0026
    • ✓ the same loop with sin q replaced by q: energy ratio vs (1 + (wh)^2)^nexpected 10.654 · got 10.654 · relative error 5.5×10⁻¹³so the shortfall at 5 deg is the pendulum's softness
    • ✓ from 30 deg, explicit Euler gains less than from 5 degobserved as statedx7.52 against x10.5
    • ✓ C++ explicit loop: energy ratio after 20 s, vs the Python runexpected 10.5334 · got 10.5334 · relative error 0
  10. RK4 numerical damping of an oscillator

    Linear oscillator. Equivalent damping ratio ≈ (ωh)⁵/144, which is negligible at small ωh, but builds up over very long runs.

    ∣R(iωh)∣2=1−(ωh)672+(ωh)8576|R(i\omega h)|^2 = 1 - \dfrac{(\omega h)^6}{72} + \dfrac{(\omega h)^8}{576}
    F7.10✓ 3/3 checked[61][64]
    Symbols and checks
    • ✓ |R(i w h)|^2 exact vs formulaexpected 1 · got 1 · relative error 1.1×10⁻¹⁶
    • ✓ RK4, 5 deg, 20 s at 2 ms: energy lost vs n (wh)^6 / 72expected 1.84004×10⁻⁹ · got 1.83447×10⁻⁹ · relative error 0.003
    • ✓ RK4: halving h cuts the loss by 2^5expected 32 · got 32.0025 · relative error 8×10⁻⁵per step (wh)^6, and twice as many steps
  11. Stability limits

    Linear system. The second is why a D-gain applied as a torque by your own code has a ceiling, K_d < 2I/h, lower once stiffness is included.

    semi-implicit Euler: ωh<2,explicit damping alone: h bI<2\text{semi-implicit Euler: } \omega h < 2,\qquad \text{explicit damping alone: } h\,\dfrac{b}{I} < 2
    F7.11✓ 5/5 checked[62]
    Symbols and checks
    • ✓ symplectic Euler: spectral radius at wh=1.99expected 1 · got 1 · relative error 3.3×10⁻¹⁶
    • ✓ symplectic Euler: unstable at wh=2.01 (rho>1)observed as stated
    • ✓ explicit damper alone (wh -> 0): eigenvalue 1 - hb/I, stable iff hb/I < 2observed as stated
    • ✓ damper plus stiffness at wh = 1: limit hb/I = 2 - (wh)^2/2 = 1.5observed as stated
    • ✓ the pendulum at 2 ms: unstable between 2 - (wh)^2/2 and 2observed as statedso stiffness lowers the damping limit, slightly at this step
08

Measuring damping and friction

Module page →
  1. Damped equation of motion, small angle

    Iθ¨+bθ˙+kθ=0,k=mgdI\ddot\theta + b\dot\theta + k\theta = 0,\qquad k = m g d
    Symbols
    SymbolMeaningUnit
    bbviscous damping coefficientN·m·s/rad
    kkgravity stiffnessN·m/rad
  2. Decay rate, damping ratio, damped frequency

    σ=b2I,ζ=b2kI=σωn,ωd=ωn1−ζ2\sigma = \dfrac{b}{2I},\qquad \zeta = \dfrac{b}{2\sqrt{kI}} = \dfrac{\sigma}{\omega_n},\qquad \omega_d = \omega_n\sqrt{1-\zeta^2}
    F8.02✓ 2/2 checked[65][66]
    Symbols and checks
    SymbolMeaningUnit
    σσenvelope decay rate1/s
    ζζdamping ratiodimensionless
    ωdω_{d}damped angular frequencyrad/s
    • ✓ b recovered as 2 I sigma, b = 1e-3 plantedexpected 0.001 · got 9.99863×10⁻⁴ · relative error 1.4×10⁻⁴
    • ✓ zeta from log decrement vs b / (2 sqrt(k I))expected 0.0111684 · got 0.0111684 · relative error 5.1×10⁻⁶
  3. Peaks lie on an exponential envelope

    Linear viscous damping, released from rest.

    ∣θn∣=θ0 e−σtn,tn=nπωd|\theta_n| = \theta_0\,e^{-\sigma t_n},\qquad t_n = \dfrac{n\pi}{\omega_d}
    F8.03✓ 2/2 checked[65][66]
    Symbols and checks
    • ✓ b recovered as 2 I sigma, b = 1e-3 plantedexpected 0.001 · got 9.99863×10⁻⁴ · relative error 1.4×10⁻⁴
    • ✓ b fitted with b = 0 planted (N m s/rad)expected 0 · got −3.78558×10⁻¹⁵ · absolute error 3.8×10⁻¹⁵the pipeline's own floor; planted values are 1e-3
  4. Logarithmic decrement

    n counts half-swing peaks, as in F8.03, so peaks n and n + 2 are one full cycle apart, on the same side.

    δ=ln⁡∣θn∣∣θn+2∣=σTd=2πζ1−ζ2,ζ=δ4π2+δ2\delta = \ln\dfrac{|\theta_n|}{|\theta_{n+2}|} = \sigma T_d = \dfrac{2\pi\zeta}{\sqrt{1-\zeta^2}},\qquad \zeta = \dfrac{\delta}{\sqrt{4\pi^2+\delta^2}}
    F8.04✓ 1/1 checked[65][66][67]
    Symbols and checks
    SymbolMeaningUnit
    δδlog decrement over one full cycledimensionless
    TdT_{d}damped periods
    • ✓ zeta from log decrement vs b / (2 sqrt(k I))expected 0.0111684 · got 0.0111684 · relative error 5.1×10⁻⁶
  5. From the fit back to the coefficient

    I is the inertia about the pivot, including any rotor that turns with the pendulum.

    b=2Iσb = 2 I \sigma
    F8.05✓ 4/4 checked[65][66]
    Symbols and checks
    • ✓ b recovered as 2 I sigma, b = 1e-3 plantedexpected 0.001 · got 9.99863×10⁻⁴ · relative error 1.4×10⁻⁴
    • ✓ b fitted with b = 0 planted (N m s/rad)expected 0 · got −3.78558×10⁻¹⁵ · absolute error 3.8×10⁻¹⁵the pipeline's own floor; planted values are 1e-3
    • ✓ b fitted at h = 2 ms (Euler) vs 1 ms (RK4)expected 0.00100004 · got 9.99863×10⁻⁴ · relative error 1.7×10⁻⁴halving the step should not move the answer you report
    • ✓ b from the return map, both plantedexpected 0.001 · got 9.99265×10⁻⁴ · relative error 7.4×10⁻⁴
  6. Inertia from the same swing

    Linear viscous model; needs k = m·g·d from a separate measurement.

    I=kωd2+σ2I = \dfrac{k}{\omega_d^2 + \sigma^2}
    F8.06✓ 1/1 checked[65][66]
    Symbols and checks
    • ✓ I from the same swing, k / (wd^2 + sigma^2)expected 0.0058208 · got 0.00582245 · relative error 2.8×10⁻⁴5 deg amplitude lengthens the period by ~0.05 %, so ~0.1 % on I
  7. Coulomb friction, straight-line decay

    Linear stiffness. Motion stops at the first turning point where k|A| is within the static friction, so inside ±Δ when static and kinetic friction are equal (as MuJoCo models them), or ±τ_s/k when static friction τ_s is larger. The pendulum then rests off-centre.

    Δ=τck,An+1=An−2Δ  (per half-swing)\Delta = \dfrac{\tau_c}{k},\qquad A_{n+1} = A_n - 2\Delta\ \ (\text{per half-swing})
    F8.07✓ 4/4 checked[65][68][69]
    Symbols and checks
    SymbolMeaningUnit
    τcτ_{c}friction torque magnitudeN·m
    ΔΔdead band half-widthrad
    AnA_{n}n-th peak amplituderad
    • ✓ mean drop per half-swing vs 2 tau_c / kexpected 0.00290418 · got 0.00290032 · relative error 0.0013
    • ✓ spread of the drops (std / mean)expected 0 · got 3.76085×10⁻⁴ · absolute error 3.8×10⁻⁴constant drop = straight line on linear axes
    • ✓ tau_c = k Delta from the interceptexpected 5×10⁻⁴ · got 4.98736×10⁻⁴ · relative error 0.0025
    • ✓ half-swings before the pendulum stopsexpected 30 · got 30 · absolute error 0motion stops at the first peak inside the dead band
  8. Peak-to-peak return map (viscous and Coulomb together)

    Linear model, half-swing peaks. Fit a straight line to A_{n+1} against A_n; the slope gives σ, the intercept gives Δ.

    An+1=q An−Δ (1+q),q=e−σTd/2A_{n+1} = q\,A_n - \Delta\,(1+q),\qquad q = e^{-\sigma T_d/2}
    F8.08✓ 5/5 checked[65][70]
    Symbols and checks
    • ✓ viscous: slope vs exp(-sigma Td / 2)expected 0.96552 · got 0.965504 · relative error 1.6×10⁻⁵
    • ✓ Coulomb: intercept vs -2 Delta (rad)expected −0.00290418 · got −0.00289417 · relative error 0.0034
    • ✓ Coulomb: slope vs 1expected 1 · got 0.999911 · relative error 8.9×10⁻⁵
    • ✓ b from the return map, both plantedexpected 0.001 · got 9.99265×10⁻⁴ · relative error 7.4×10⁻⁴
    • ✓ tau_c = k Delta from the interceptexpected 5×10⁻⁴ · got 4.98736×10⁻⁴ · relative error 0.0025
  9. Equivalent viscous damping of Coulomb friction

    Energy balance over one cycle (4τ_cA = πbωA²). Rises as amplitude falls, which is the signature that gives Coulomb away.

    ζeq(A)=2 τcπ k A\zeta_{\text{eq}}(A) = \dfrac{2\,\tau_c}{\pi\,k\,A}
    F8.09✓ 1/1 checked[65][71]
    Symbols and checks
    • ✓ apparent zeta of Coulomb decay vs 2 tau_c / (pi k A)expected 0.0119878 · got 0.0119903 · relative error 2×10⁻⁴
  10. Bias of MuJoCo's implicit joint damping

    Semi-implicit Euler with implicit joint damping, linear oscillator. Relative bias ≈ −hσ = −hζω_n, negligible for light damping.

    σnum=ln⁡(1+2hσ)2h≈σ (1−hσ)\sigma_{\text{num}} = \dfrac{\ln(1+2h\sigma)}{2h} \approx \sigma\,(1 - h\sigma)
    F8.10✓ 2/2 checked[46][72]
    Symbols and checks
    • ✓ MuJoCo Euler decay rate at zeta=0.2 vs ln(1+2h sigma)/(2h)expected 1.53354 · got 1.53354 · relative error 2.7×10⁻⁶true sigma 1.53825; predicted relative bias -3.06e-03
    • ✓ b fitted at h = 2 ms (Euler) vs 1 ms (RK4)expected 0.00100004 · got 9.99863×10⁻⁴ · relative error 1.7×10⁻⁴halving the step should not move the answer you report
  11. Braking from a shorted motor winding

    One winding (the brushed DC model), shorted through R, with the electrical time constant L/R much shorter than the swing. K_t = K_e follows from power balance for an ideal motor. Open-circuit windings carry no current and add no braking.

    bshort=KtKeR=K2R,K=Kt=Ke (SI units)b_{\text{short}} = \dfrac{K_t K_e}{R} = \dfrac{K^2}{R},\qquad K = K_t = K_e\ \text{(SI units)}
    F8.11✓ 1/1 checked[3][73][74][75]
    Symbols and checks
    SymbolMeaningUnit
    KtK_{t}torque constantN·m/A
    KeK_{e}back-emf constantV·s/rad
    RRtotal resistance around the shorted loopΩ
    • ✓ b fitted from the coupled model vs K^2/Rexpected 0.001 · got 0.00100005 · relative error 5.2×10⁻⁵illustrative K = 0.1 N m/A, R = 10 ohm, L = 1 mH
09

Checking the model against reality

Module page →
  1. Gravity stiffness from a static balance

    Pendulum held horizontal, pivot free to turn (off the motor, so cogging cannot hold part of the load). Pivot friction can carry up to its static torque either way: average a reading taken after lowering onto the scale with one taken after pressing down and releasing.

    k=mgd=WsLs=mread g Lsk = m g d = W_s L_s = m_{\text{read}}\, g\, L_s
    Symbols
    SymbolMeaningUnit
    WsW_{s}force on a scale under the far endN
    mreadm_{\text{read}}reading of a scale calibrated with a known mass on the benchkg
    LsL_{s}pivot to the scale's contact pointm
  2. Inertia the dynamics actually see

    Includes every rotating part (rotor, hub, screws). Correct the measured period for amplitude first (F6.09).

    Itotal=kωn2,ωn2=ωd2+σ2I_{\text{total}} = \dfrac{k}{\omega_n^2},\qquad \omega_n^2 = \omega_d^2 + \sigma^2
    F9.02✓ 1/1 checked[65][66]
    Symbols and checks
    • ✓ I from the same swing, k / (wd^2 + sigma^2)expected 0.0058208 · got 0.00582245 · relative error 2.8×10⁻⁴5 deg amplitude lengthens the period by ~0.05 %, so ~0.1 % on I
  3. Error budget for the measured inertia

    From I = m_read g L_s T²/(4π²): each input enters once, the period squared. Independent, small relative errors (first-order propagation, added in quadrature). Use the worst-case sum if errors may be correlated.

    (δII)2≈(δmreadmread)2+(δLsLs)2+(2 δTT)2+(δgg)2\Big(\dfrac{\delta I}{I}\Big)^2 \approx \Big(\dfrac{\delta m_{\text{read}}}{m_{\text{read}}}\Big)^2 + \Big(\dfrac{\delta L_s}{L_s}\Big)^2 + \Big(2\,\dfrac{\delta T}{T}\Big)^2 + \Big(\dfrac{\delta g}{g}\Big)^2
    F9.03✓ 1/1 checked[78][79]
    Symbols and checks
    • ✓ quadrature budget vs Monte Carlo spread of Iexpected 0.0032209 · got 0.00322052 · relative error 1.2×10⁻⁴400000 random draws of scale, length, period and g
  4. Local gravity (normal gravity on the ellipsoid, plus height)

    Normal gravity is a smooth model of the whole Earth. Real gravity at a site departs from it by local anomalies, quoted in milligals (1 mGal = 10⁻⁵ m/s², about 10⁻⁶ of g). Where the anomaly is around 100 mGal (10⁻⁴ of g), it is several times smaller than the error of assuming 9.81 m/s² at most mid-latitudes, though near 49° latitude 9.81 happens to be right.

    g(φ,h)≈ge 1+kssin⁡2φ1−e2sin⁡2φ−3.086×10−6 hg(\varphi, h) \approx g_e\,\dfrac{1 + k_s \sin^2\varphi}{\sqrt{1 - e^2\sin^2\varphi}} - 3.086\times10^{-6}\,h
    F9.04✓ 5/5 checked[80][81][82][83][84]
    Symbols and checks
    SymbolMeaningUnit
    φφgeodetic latituderad
    hhheight above the ellipsoidm
    geg_{e}equatorial normal gravity 9.7803253359m/s²
    ksk_{s}normal gravity constant 0.00193185265241dimensionless
    e2e²first eccentricity squared 0.00669437999013dimensionless
    • ✓ g_e derived vs 9.7803253359expected 9.78033 · got 9.78033 · relative error 4.2×10⁻¹³
    • ✓ k_s derived vs 0.00193185265241expected 0.00193185 · got 0.00193185 · relative error 1.5×10⁻¹²
    • ✓ e^2 derived vs 0.00669437999013expected 0.00669438 · got 0.00669438 · relative error 1.7×10⁻¹²
    • ✓ Somigliana vs 1980 series, 40 N 100 mexpected 9.80139 · got 9.80139 · relative error 2.1×10⁻⁷
    • ✓ normal gravity at 45 deg, sea level, vs standard gravity 9.80665expected 9.80665 · got 9.8062 · relative error 4.6×10⁻⁵standard gravity was based on sea level at 45 deg
  5. How sharply a zero crossing and a peak can be timed

    Small swing, θ = A cos ωt, and δθ ≪ A. The angle moves fastest at a zero crossing and not at all at a peak, so time the period between zero crossings. Δt grows as the swing decays (Δt_zero ∝ 1/A).

    Δtzero=δθA ω,Δtpeak=22 δθA ω2,ΔtpeakΔtzero=22Aδθ\Delta t_{\text{zero}} = \dfrac{\delta\theta}{A\,\omega},\qquad \Delta t_{\text{peak}} = 2\sqrt{\dfrac{2\,\delta\theta}{A\,\omega^2}},\qquad \dfrac{\Delta t_{\text{peak}}}{\Delta t_{\text{zero}}} = 2\sqrt{\dfrac{2A}{\delta\theta}}
    F9.05✓ 2/2 checked[85]
    Symbols and checks
    SymbolMeaningUnit
    ΔtzeroΔt_{\text{zero}}time to cross one count at a zero crossings
    ΔtpeakΔt_{\text{peak}}time spent in the top count at a peaks
    δθδθangle resolution (one encoder count)rad
    AAswing amplituderad
    • ✓ time spent in the top count at a peak (s)expected 0.0487567 · got 0.04885 · relative error 0.001912-bit encoder, 5 deg swing, MuJoCo RK4
    • ✓ time to cross one count at a zero crossing (s)expected 0.00228547 · got 0.00228 · relative error 0.0024
  6. Period uncertainty from timing many cycles

    Independent crossing errors and a good clock. With damping the last crossing is the less certain (F9.05), so for a period taken from the first and last crossings, timing more cycles stops helping: with decay rate σ the error is smallest near N = x/(σT), where x solves x = 1 + e^(−2x) (x ≈ 1.11). A least-squares fit to every crossing has no such optimum.

    δTT=δt02+δtN2N T\dfrac{\delta T}{T} = \dfrac{\sqrt{\delta t_0^2 + \delta t_N^2}}{N\,T}
    F9.06✓ 1/1 checked[78][79]
    Symbols and checks
    SymbolMeaningUnit
    δt0δt_{0}uncertainty of the first crossing times
    δtNδt_{N}uncertainty of the last crossing times
    NNwhole cycles between themdimensionless
    • ✓ best number of cycles: x = 1 + exp(-2x) vs brute forceexpected 15.8008 · got 15.801 · relative error 1.5×10⁻⁵with the M8 viscous example, b = 1e-3
  7. When the bench and the model agree

    Independent uncertainties, roughly normal. With coverage factor 2 this is the E_n ≤ 1 criterion of ISO 13528, written with standard uncertainties. A larger gap means something is unaccounted for, in the model or in the bench's budget, or, about one time in twenty, chance. A smaller gap means the test cannot tell.

    ∣xbench−xmodel∣≤2 ubench2+umodel2|x_{\text{bench}} - x_{\text{model}}| \le 2\,\sqrt{u_{\text{bench}}^2 + u_{\text{model}}^2}
    Symbols
    SymbolMeaningUnit
    uustandard uncertainty of each valueunits of x
  8. Standard gravity is a defined constant, not your gravity

    Adopted in 1901, based on sea level at 45° latitude. MuJoCo's default 9.81 is close to it; neither is the gravity on your bench (F9.04).

    gn=9.80665 m/s2 (exact, by definition)g_n = 9.80665\ \text{m/s}^2\ \text{(exact, by definition)}
    F9.08✓ 1/1 checked[36][87]
    Symbols and checks
    • ✓ normal gravity at 45 deg, sea level, vs standard gravity 9.80665expected 9.80665 · got 9.8062 · relative error 4.6×10⁻⁵standard gravity was based on sea level at 45 deg

Modules

Most modules follow the same shape: key ideas, formulas or code rules, a worked example, best practice, questions, and sources to watch and read. A module is linked once it has a page. “Ready” means it has passed the independent fact-check and the author's review; “in review” means it has not yet. A planned module may instead link to a reading list, with no formulas until the code it describes exists.

  1. 00

    How to learn this

    Worked examples first, then less help each time. Predict before you measure. Why watching is not the same as being able to write it.

    ready
  2. 01

    Bench and safety

    Current limit first, logic analyser versus oscilloscope, what happens when power drops, safe stops.

    ready
  3. 02

    Development environment

    A clean macOS toolchain for C++ and Python, with CMake presets, Ninja, clangd and clang-format.

    ready
  4. 03

    Modern C++ for robotics code

    Owning resources with RAII, unique_ptr and custom deleters, the rules of zero and five, move semantics, wrapping C libraries.

    ready
  5. 04

    Build, test and sanitizers

    CMake targets, GoogleTest, tests that fail first, independent expected values, sanitizers as diagnosis not cure.

    ready
  6. 05

    MuJoCo essentials

    The XML model, where mass and inertia come from, the step loop, the mass matrix, energy, armature, gravity.

    ready
  7. 06

    Pendulum physics

    Inertia and the parallel-axis theorem, natural frequency and period, large swings, energy.

    ready
  8. 07

    Numerical integration

    The Euler family and RK4, order of accuracy, why some methods keep energy and others drift, convergence studies.

    in review
  9. 08

    Measuring damping and friction

    Decay rate, damping ratio and log decrement; Coulomb friction's straight-line decay; separating the two; the traps.

    ready
  10. 09

    Checking the model against reality

    Verification versus validation, measuring stiffness and inertia on the bench, error budgets, local gravity.

    ready
  11. 10

    Control and estimation

    Controllers and a state estimator for the arm, added as they are built and checked. A reading list for now.

    planned

Sources

  1. [1]

    University Physics Volume 2, §9.5 Electrical Energy and Power (opens in a new tab)

    Samuel J. Ling, Jeff Sanny, William Moebs · OpenStax, 2016. CC BY 4.0

    Eq. 9.12 (P = IV)

    Electrical power.

    read
  2. [2]

    SPD Constant Current (operating tip) (opens in a new tab)

    Siglent Technologies North America

    The supply stays in CV while the load draws less than the limit and switches to CC when it would draw more (worked example with 20 Ω and 10 Ω loads).

    read
  3. [3]

    University Physics Volume 2, §9.4 Ohm's Law (opens in a new tab)

    Samuel J. Ling, Jeff Sanny, William Moebs · OpenStax, 2016. CC BY 4.0

    Eq. 9.11 (V = IR)

    Ohm's law, used for the current a back-emf drives through a shorted winding.

    read
  4. [4]

    What Sampling Rate Should I Use? (opens in a new tab)

    Saleae support

    Sample digital signals at least 4× their bandwidth, analog at least 10×.

    read
  5. [5]

    cmake-presets(7) (opens in a new tab)

    Kitware, CMake documentation

    Schema versions (version 6, CMake 3.25: workflow presets); configurePresets.inherits

    Presets file versions and the CMake release that added each; how inherits works. Read from the documentation source in the CMake repository (master, October 2026).

    read
  6. [6]

    CMAKE_EXPORT_COMPILE_COMMANDS (opens in a new tab)

    Kitware, CMake documentation

    Writes compile_commands.json with the exact compiler call for every source file; Makefile and Ninja generators only. Read from the documentation source in the CMake repository (master, October 2026).

    read
  7. [7]

    Getting started (project setup) (opens in a new tab)

    clangd documentation, LLVM

    Project setup: compile_commands.json

    clangd looks for compile_commands.json in the parent directories of the file being edited and in subdirectories named build/. Read from the llvm/clangd-www repository (September 2026).

    read
  8. [8]

    Configuration (opens in a new tab)

    clangd documentation, LLVM

    CompileFlags: CompilationDatabase

    CompilationDatabase names the directory to search for compile_commands.json. Read from the llvm/clangd-www repository.

    read
  9. [9]

    FetchContent (opens in a new tab)

    Kitware, CMake documentation

    FetchContent_Declare: SYSTEM (added in 3.25); advice to use a commit hash for GIT_TAG

    SYSTEM makes FetchContent_MakeAvailable add the dependency with add_subdirectory(... SYSTEM); for content from servers you do not control, a commit hash is advised over a branch or tag name. Read from the documentation source in the CMake repository (master, October 2026).

    read
  10. [10]

    ExternalProject (Git options, shared by FetchContent) (opens in a new tab)

    Kitware, CMake documentation

    GIT_TAG; GIT_SHALLOW

    GIT_SHALLOW clones only the commit named by GIT_TAG, and then works only with branch and tag names, not a commit hash. Read from the CMake repository.

    read
  11. [11]

    SYSTEM (target property) (opens in a new tab)

    Kitware, CMake documentation

    A system target's interface include directories are treated as system include directories when compiling its consumers. Read from the documentation source in the CMake repository (master, October 2026).

    read
  12. [13]

    cmake-buildsystem(7) (opens in a new tab)

    Kitware, CMake documentation

    Static Libraries; Transitive Link Properties (INTERFACE_LINK_OPTIONS)

    Static libraries are archives, so CMake records their link dependencies for transitive use when linking the binaries that consume them; link usage requirements such as INTERFACE_LINK_OPTIONS travel as transitive link properties. Read from the CMake repository.

    read
  13. [14]

    Effective CMake (slides) (opens in a new tab)

    Daniel Pfeifer · C++Now 2017, on Speaker Deck

    Think in targets and their usage requirements; prefer target_* commands to directory-wide ones; -Wall is not a usage requirement (slide 20); never pass -Werror to the compiler, and treat new warnings as errors instead, burning existing ones down (slides 44–46).

    read
  14. [15]

    Locking and syncing (opens in a new tab)

    Astral, uv documentation

    Locking and syncing are automatic: uv run locks and syncs before running; --locked makes an out-of-date lockfile an error. Read from the uv repository.

    read
  15. [16]

    Running commands in projects (opens in a new tab)

    Astral, uv documentation

    uv run runs a command in the project environment and makes sure it is up to date first. Read from the uv repository (October 2026).

    read
  16. [17]

    Project structure and files (opens in a new tab)

    Astral, uv documentation

    The lockfile

    uv.lock holds the exact resolved versions and should be checked into version control; .venv should not. Read from the uv repository.

    read
  17. [18]

    Working Draft, Standard for Programming Language C++ (N4861), General utilities (opens in a new tab)

    ISO/IEC JTC1/SC22/WG21, April 2020 (the C++20 working draft)

    [unique.ptr.single.dtor]; [unique.ptr.single.ctor] (move constructor postconditions)

    unique_ptr's destructor does nothing if get() == nullptr and otherwise calls get_deleter()(get()); after a move construction, u.get() == nullptr.

    read
  18. [19]

    C++ Core Guidelines: R.1, R.20, R.21, E.6 (opens in a new tab)

    Bjarne Stroustrup, Herb Sutter (editors) · Standard C++ Foundation

    R.1 (RAII), R.20 (smart pointers for ownership), R.21 (prefer unique_ptr to shared_ptr), E.6 (RAII to prevent leaks)

    Wrap every acquire/release pair in an object that acquires in its constructor and releases in its destructor; express ownership with smart pointers; unique_ptr is simpler, more predictable and faster than shared_ptr, which maintains a use count. Read from the guidelines repository.

    read
  19. [20]

    Working Draft, Standard for Programming Language C++ (N4861), Classes (opens in a new tab)

    ISO/IEC JTC1/SC22/WG21, April 2020 (the C++20 working draft)

    [class.dtor] (members destroyed in reverse order of construction); [class.base.init] (members initialized in declaration order)

    Non-static data members are initialized in the order they are declared, whatever the initializer list says, and destroyed in the reverse order.

    read
  20. [21]

    C++ Core Guidelines: C.20, C.21, C.47, C.66 (opens in a new tab)

    Bjarne Stroustrup, Herb Sutter (editors) · Standard C++ Foundation

    C.20 (rule of zero), C.21 (rule of five), C.47 (member declaration order), C.66 (noexcept moves)

    Avoid defining default operations when you can; if you define or delete any copy, move or destructor function, define or delete them all; members are initialized in declaration order. Read from the guidelines repository (August 2026).

    read
  21. [22]

    Back to Basics: RAII and the Rule of Zero (slides) (opens in a new tab)

    Arthur O'Dwyer · CppCon 2019; official slides in the CppCon/CppCon2019 repository

    Slides 38–46 (RAII and exception safety; the Rule of Zero)

    RAII and exception safety; classes that only use library components should write no special member functions (the Rule of Zero). The talk is also on the CppCon YouTube channel.

    read
  22. [23]

    Working Draft, Standard for Programming Language C++ (N4861), Library introduction (opens in a new tab)

    ISO/IEC JTC1/SC22/WG21, April 2020 (the C++20 working draft)

    [lib.types.movedfrom]

    Unless otherwise specified, moved-from standard library objects are placed in a valid but unspecified state.

    read
  23. [24]

    Back to Basics: Move Semantics (part 1 of 2) (opens in a new tab)

    Klaus Iglberger · CppCon 2019, CppCon YouTube channel

    std::move, rvalue references, moved-from objects, noexcept move operations and the rules of zero and five. Topics confirmed from the official slides (CppCon/CppCon2019 repository); video id from a listing of the CppCon channel.

    listed
  24. [25]

    IEEE Std 754-2019, IEEE Standard for Floating-Point Arithmetic (opens in a new tab)

    IEEE, 2019 (also ISO/IEC 60559:2020)

    binary64 (double) has a 52-bit fraction field, hence ε = 2⁻⁵².

    listed
  25. [26]

    std::numeric_limits<T>::epsilon (opens in a new tab)

    cppreference.com

    Machine epsilon is the gap between 1.0 and the next representable value (DBL_EPSILON for double; 2⁻⁵² checked numerically).

    read
  26. [27]

    What Every Computer Scientist Should Know About Floating-Point Arithmetic (opens in a new tab)

    David Goldberg · ACM Computing Surveys, March 1991 (reprinted as Appendix D of the Oracle Numerical Computation Guide)

    Rounding error bounds per operation (at most ε relative for a correctly rounded multiply); why exact equality tests on computed doubles fail.

    read
  27. [28]

    GoogleTest Assertions Reference (opens in a new tab)

    Google, GoogleTest (docs/reference/assertions.md)

    EXPECT_NEAR(val1, val2, abs_error); EXPECT_DOUBLE_EQ (within 4 ULPs); EXPECT_* continues after failure, ASSERT_* aborts the current function. Read from the GoogleTest repository's docs.

    read
  28. [29]

    GoogleTest Primer (opens in a new tab)

    Google

    Assertions

    ASSERT_* failures are fatal and abort the current function; EXPECT_* failures are not, and are usually preferred. Read from the googletest repository (October 2026).

    read
  29. [30]

    AddressSanitizer (opens in a new tab)

    Clang documentation, LLVM 18

    Introduction; Usage

    Detects out-of-bounds accesses, use-after-free, use-after-return and use-after-scope, double free; typical slowdown 2×; compile and link with -fsanitize=address, add -fno-omit-frame-pointer for better stack traces. Read from llvm-project at llvmorg-18.1.8.

    read
  30. [31]

    UndefinedBehaviorSanitizer (opens in a new tab)

    Clang documentation, LLVM 18

    Usage; Available checks

    -fno-sanitize-recover makes a check print its report and exit instead of continuing; signed-integer-overflow is one of the checks. Read from llvm-project at llvmorg-18.1.8.

    read
  31. [32]

    AddressSanitizerContainerOverflow (opens in a new tab)

    google/sanitizers wiki, GitHub

    Container-overflow is an access inside a vector's allocation but past its size; libc++ annotates std::vector; mixing instrumented and uninstrumented code can give false positives, worked around by building everything with ASan or by ASAN_OPTIONS=detect_container_overflow=0. Read from the wiki's git repository.

    read
  32. [33]

    Compiled checks for modules 02 to 04 (tools/robotics/cpp)

    A small CMake project that mirrors the arm repository, built with presets and run by verify.py; every C++, CMake and GoogleTest claim marked checked is observed there.

    derived
  33. [34]

    Back to Basics: Unit Testing in C++ (opens in a new tab)

    Dave Steffen · CppCon 2024; posted on isocpp.org

    The principles behind common unit-testing advice, such as writing tests first and testing error conditions separately, and where they conflict.

    listed
  34. [35]

    GoogleTest (CMake module) (opens in a new tab)

    Kitware, CMake documentation

    gtest_discover_tests: DISCOVERY_MODE (added in 3.18)

    POST_BUILD discovers tests at build time; PRE_TEST delays discovery until just before the tests run, where run-time dependencies are more likely to be found. Read from the documentation source in the CMake repository (master, October 2026).

    read
  35. [36]

    MuJoCo XML Reference (3.17.0) (opens in a new tab)

    Google DeepMind

    option-timestep (default 0.002 s; RK4 costs about four times per step); option-gravity (default 0 0 −9.81); option-integrator; option-flag-energy; option-flag-eulerdamp (implicit joint damping in Euler, on by default); body-joint-armature (reflected inertia, gear ratio squared; positive armature improves stability); actuator-general-armature (rotor inertia, scaled by gear squared); body-joint-damping (Euler treats joint damping implicitly); body-joint-frictionloss; compiler-inertiafromgeom; body-geom-density (default 1000 kg/m³, used only when mass is not given)

    MuJoCo defaults, energy definitions, armature, damping and friction-loss behaviour. Read from the 3.17.0 source of the docs (doc/XMLreference.rst).

    read
  36. [37]

    mj_energyPos, src/engine/engine_sensor.c (MuJoCo 3.17.0) (opens in a new tab)

    Google DeepMind, GitHub

    Potential energy = −Σ m_b g·x_b (body centres of mass), so zero height is the world origin.

    read
  37. [38]

    Modern Robotics — Mechanics, Planning, and Control (opens in a new tab)

    Kevin M. Lynch, Frank C. Park · Cambridge University Press, 2017. Free preprint for personal use at the book site.

    §8.1.2 General Formulation (p. 275), §8.1.3 Understanding the Mass Matrix (p. 277), §8.9.2 Apparent Inertia (p. 311), §8.9.4 Friction (p. 315)

    Manipulator dynamics M(θ)θ̈ + c(θ,θ̇) + g(θ) = τ, kinetic energy ½θ̇ᵀMθ̇, apparent (reflected) inertia through gearing, friction models. Section titles and pages confirmed from the preprint's table of contents.

    listed
  38. [39]

    University Physics Volume 1, §10.4 Moment of Inertia and Rotational Kinetic Energy (opens in a new tab)

    William Moebs, Samuel J. Ling, Jeff Sanny · OpenStax (Rice University), 2016. CC BY 4.0

    Eq. 10.18 (K = ½Iω²); Fig. 10.20 (table of common shapes, an image)

    Rotational kinetic energy. The shape table is an image, so the sphere and cylinder values are also cited from other sources on this page.

    read
  39. [40]

    MuJoCo Modeling chapter, solver parameters and friction (3.17.0) (opens in a new tab)

    Google DeepMind

    Solver parameters: solref default "0.02 1" (time constant, damping ratio 1: critically damped); timeconst at least twice the timestep (enforced unless refsafe is off); Restitution (zero damping in the direct format); friction loss is first-order, purely damped, no exact stick (slow slippage)

    Constraints are soft mass-spring-dampers, critically damped by default; restitution needs the direct format with zero damping, and even then energy only fluctuates around its initial value. Why simulated friction loss creeps instead of sticking.

    read
  40. [41]

    src/engine/engine_core_constraint.c (MuJoCo 3.17.0) (opens in a new tab)

    Google DeepMind, GitHub

    solref safety: solref[0] raised to 2·timestep unless refsafe is disabled (standard format, non-discrete integrators)

    With refsafe enabled and solref in the standard format, a time constant below twice the timestep is raised to it, except under the discrete integrator, which uses a different safeguard.

    read
  41. [42]

    MuJoCo Programming chapter, Simulation (3.17.0) (opens in a new tab)

    Google DeepMind

    Initialization; Simulation loop (mj_step, mj_step1, mj_step2); State and control (integration state)

    mjModel and mjData are allocated by API functions; the load functions return NULL on an error or a warning, and the XML loader writes the reason into the buffer passed to it; mjData is specific to its mjModel. mj_step computes forward dynamics at the current time, then integrates; splitting it into mj_step1 and mj_step2 works only with the single-step integrators. The integration state is everything forward dynamics reads. Read from the 3.17.0 source of the docs.

    read
  42. [43]

    mj_RungeKutta and mj_forwardSkip, src/engine/engine_forward.c (MuJoCo 3.17.0) (opens in a new tab)

    Google DeepMind, GitHub

    RK4 evaluates forward dynamics at each intermediate stage with skipsensor set and a comment saying energy is not recomputed, but mj_forwardSkip recomputes energy whenever its own flags are clear, so energy is recomputed at every stage; the last evaluation is at the final stage. The Computation chapter says the optional computations run only once.

    read
  43. [44]

    include/mujoco/mjmodel.h and mjdata.h (MuJoCo 3.17.0) (opens in a new tab)

    Google DeepMind, GitHub

    nq: number of generalized coordinates = dim(qpos); nv: degrees of freedom = dim(qvel); jnt_qposadr, jnt_dofadr

    The sizes of qpos and qvel and the per-joint start addresses into each, as declared in the public headers.

    read
  44. [45]

    MuJoCo Overview (3.17.0) (opens in a new tab)

    Google DeepMind

    Separation of model and data; Examples (the text version of a compiled model); Clarifications: Units are unspecified

    mjModel holds the model description and is expected to remain constant; mjData holds all dynamic variables and intermediate results and is constructed given an mjModel, so one model can run many states. Saved as text, a compiled model shows all of mjModel, revealing what the compiler did. MuJoCo does not fix physical units; any consistent system works, but the defaults (gravity 9.81, density 1000) assume MKS. Read from the 3.17.0 source of the docs.

    read
  45. [46]

    MuJoCo Computation chapter, Numerical integration (3.17.0) (opens in a new tab)

    Google DeepMind

    explicit, semi-implicit and implicit-in-velocity Euler; D matrix; implicitfast drops Coriolis and centripetal terms; discrete integrator; §Friction loss (dry friction modelled as a constraint whose effect is to drive the joint velocity to zero); §Reproducibility; §Numerical integration, RK4 and the tip “Choosing timestep and integrator”

    The exact update equations of every MuJoCo integrator, and how friction loss is modelled. The docs recommend implicitfast for most models (similar cost to Euler, more stable), keep Euler for compatibility, and call RK4 best for energy-conserving or nearly conserving systems; they report RK4 qualitatively better than single-step methods on an energy-conserving example even at a quarter of the timestep, and single-step methods with implicit velocity-dependent forces significantly more stable than RK4 when those forces are large.

    read
  46. [47]

    MuJoCo API Reference, Functions (3.17.0) (opens in a new tab)

    Google DeepMind

    mj_printModel, mj_printFormattedModel, mj_printData; mj_name2id

    mj_printModel prints the model to a text file, and mj_printFormattedModel does so with a printf-style float format; mj_name2id returns the id of the named object of a given type, or −1 if there is none. Read from the 3.17.0 source of the docs and include/mujoco/mujoco.h.

    read
  47. [48]

    src/engine/engine_print.c (MuJoCo 3.17.0) (opens in a new tab)

    Google DeepMind, GitHub

    mj_printModel uses the float format "% -9.2g", two significant figures; mj_printFormattedModel takes the format as an argument.

    read
  48. [49]

    mj_loadXML, src/xml/xml_api.cc (MuJoCo 3.17.0) (opens in a new tab)

    Google DeepMind, GitHub

    On a compile warning, mj_loadXML copies the warning text into the caller’s error buffer and still returns the model; on success with no warning it clears the buffer.

    read
  49. [50]

    List of moments of inertia (opens in a new tab)

    Wikipedia

    Solid sphere 2/5 mr²; solid cylinder about a transverse central axis m(3r²+h²)/12. Secondary source, cross-checked against MuJoCo's own inertia code and numerically.

    read
  50. [51]

    mjCGeom::SetInertia, src/user/user_objects.cc (MuJoCo 3.17.0) (opens in a new tab)

    Google DeepMind, GitHub

    MuJoCo computes a solid sphere as 2mr²/5 and a solid cylinder as m(3r²+h²)/12 with h the full length (size[1] is the half-length).

    read
  51. [52]

    University Physics Volume 1, §10.5 Calculating Moments of Inertia (opens in a new tab)

    William Moebs, Samuel J. Ling, Jeff Sanny · OpenStax, 2016. CC BY 4.0

    Eq. 10.20 (parallel-axis theorem); Figs. 10.25 and 10.26 (thin rod about centre, about end)

    Parallel-axis theorem; thin rod about its centre (mL²/12) and end (mL²/3).

    read
  52. [53]

    University Physics Volume 1, §9.6 Center of Mass (opens in a new tab)

    William Moebs, Samuel J. Ling, Jeff Sanny · OpenStax, 2016. CC BY 4.0

    Eq. 9.29 (r_CM = Σ m_j r_j / M)

    Centre of mass of a system of parts.

    read
  53. [54]

    University Physics Volume 1, §15.4 Pendulums (opens in a new tab)

    William Moebs, Samuel J. Ling, Jeff Sanny · OpenStax, 2016. CC BY 4.0

    Eq. 15.21 (physical pendulum, T = 2π√(I/mgL)); small-angle note (under 15°, sin θ and θ differ by under 1 %)

    Physical (compound) pendulum period and the small-angle assumption.

    read
  54. [55]

    The AGM Simple Pendulum (opens in a new tab)

    Mark B. Villarino · arXiv:1202.2782v2 [math.CA], 2014

    exact period T = 4√(l/g)·K(k), k = sin(α/2); series 1 + α²/16 + 11α⁴/3072 + 173α⁶/737280 + …

    Large-amplitude period, exact and as a series. Applies to the compound pendulum with l replaced by the equivalent length ℓ = I/(md).

    read
  55. [56]

    scipy.special.ellipk (opens in a new tab)

    SciPy documentation (1.9.1)

    SciPy's K takes the parameter m = k², not the modulus k. A common source of wrong large-amplitude periods.

    read
  56. [57]

    Effect of a small added mass on the equivalent length (centre of oscillation)

    F6.12, checked by letting MuJoCo compose the inertia and centre of mass with the added part.

    derived
  57. [58]

    Geometric numerical integration illustrated by the Störmer–Verlet method (opens in a new tab)

    Ernst Hairer, Christian Lubich, Gerhard Wanner · Acta Numerica 2003, Cambridge University Press, pp. 399–450. doi:10.1017/CBO9780511550157.006

    §1 (symplectic Euler defined); §3 (Kepler example — no drift for symplectic, drift for explicit Runge–Kutta); §4 (modified Hamiltonian, backward error analysis); §5.1 (energy approximately preserved over very long times); §5.4 (oscillations in H of size proportional to h)

    Why symplectic Euler’s energy error stays bounded, and why explicit Runge–Kutta methods drift (the paper’s general statement; it does not single out RK4).

    read
  58. [60]

    Numerical Methods for Ordinary Differential Equations, 3rd edition (opens in a new tab)

    J. C. Butcher · Wiley, 2016. ISBN 978-1-119-12150-3

    Runge–Kutta methods, order, stability functions.

    listed
  59. [61]

    Solving Ordinary Differential Equations I — Nonstiff Problems, 2nd revised edition (opens in a new tab)

    Ernst Hairer, Syvert P. Nørsett, Gerhard Wanner · Springer, 1993. ISBN 978-3-540-56670-0

    Order of accuracy, the classical RK4 method and its stability function.

    listed
  60. [62]

    Invariant, energy wobble, frequency shift and stability of semi-implicit Euler on q̈ = −ω²q

    F7.06–F7.08, F7.11. Consistent with Hairer, Lubich & Wanner (2003) §4–5, which give the general result (bounded energy error of size O(h)).

    derived
  61. [63]

    Energy growth of explicit Euler on q̈ = −ω²q

    F7.09.

    derived
  62. [64]

    RK4 amplification factor on q̈ = −ω²q from its stability function R(z) = 1 + z + z²/2 + z³/6 + z⁴/24

    F7.10.

    derived
  63. [65]

    Engineering Vibration, 4th edition (opens in a new tab)

    Daniel J. Inman · Pearson, 2014. ISBN 978-0-273-78521-7 (international edition)

    Standard reference for viscous damping, logarithmic decrement and Coulomb damping. Listed for further reading; every formula that cites it also cites a source checked on this page.

    listed
  64. [66]

    University Physics Volume 1, §15.5 Damped Oscillations (opens in a new tab)

    William Moebs, Samuel J. Ling, Jeff Sanny · OpenStax, 2016. CC BY 4.0

    Eq. 15.24 (underdamped solution, exponential envelope), Eq. 15.26 (damped frequency); under-, critically and over-damped conditions

    Exponential envelope e^(−bt/2m), damped frequency, damping regimes. (Translational form; the rotational form swaps m→I, k→mgd.)

    read
  65. [67]

    Logarithmic decrement (opens in a new tab)

    Wikipedia

    Definition (natural log of the ratio of successive peaks, or of peaks n periods apart) and when it applies (underdamped; precision falls as ζ rises past about 0.5). The page's equations did not render when checked, so the ζ relations are derived here from OpenStax Eqs. 15.24 and 15.26.

    read
  66. [68]

    Free Vibration of Damped System (contd.), Module 4 Lecture 3 (lecture notes, PDF) (opens in a new tab)

    NPTEL (National Programme on Technology Enhanced Learning, India), course 101105022

    Coulomb damping loses 2F/k per half cycle and 4F/k per cycle (linear decay). The notes take static friction as larger than kinetic.

    read
  67. [69]

    Where dry friction stops a swing (static moment balance at a turning point)

    The dead band in F8.07, checked by counting half-swings in MuJoCo.

    derived
  68. [70]

    Half-swing return map with viscous and Coulomb damping (linear stiffness)

    F8.08.

    derived
  69. [71]

    Equivalent viscous damping of Coulomb friction from energy per cycle

    F8.09.

    derived
  70. [72]

    Decay-rate bias of semi-implicit Euler with implicitly treated joint damping

    F8.10. Matched MuJoCo 3.17 to 3×10⁻⁶ at ζ = 0.2.

    derived
  71. [73]

    University Physics Volume 2, §13.6 Electric Generators and Back Emf (opens in a new tab)

    Samuel J. Ling, Jeff Sanny, William Moebs · OpenStax, 2016. CC BY 4.0

    Back emf and Fig. 13.32

    A turning motor generates a back emf that is zero at rest and rises in proportion to the motor's angular velocity.

    read
  72. [74]

    University Physics Volume 2, §11.5 Force and Torque on a Current Loop (opens in a new tab)

    Samuel J. Ling, Jeff Sanny, William Moebs · OpenStax, 2016. CC BY 4.0

    Eqs. 11.19, 11.21 (μ = NIA) and 11.22 (τ = μ × B)

    Torque on a coil in a magnetic field is proportional to the current through it.

    read
  73. [75]

    Braking from a shorted winding (back emf, Ohm’s law, torque proportional to current)

    F8.11, checked against an independent simulation of the coupled pendulum and RL circuit.

    derived
  74. [76]

    University Physics Volume 1, §12.1 Conditions for Static Equilibrium (opens in a new tab)

    William Moebs, Samuel J. Ling, Jeff Sanny · OpenStax, 2016. CC BY 4.0

    Eq. 12.5 (net torque zero); weight acts at the centre of mass in a uniform field

    The static moment balance used to measure m·g·d.

    read
  75. [77]

    The Difference Between Force and Mass (opens in a new tab)

    Morehouse Instrument Company, 7 January 2025

    The force a 1 kg mass exerts varies by up to 0.539 % worldwide with local gravity; an instrument calibrated with mass weights and no gravity correction is calibrated for mass, not force.

    read
  76. [78]

    JCGM 100:2008, Evaluation of measurement data — Guide to the expression of uncertainty in measurement (GUM) (opens in a new tab)

    Joint Committee for Guides in Metrology / BIPM. doi:10.59161/JCGM100-2008E

    Combining independent uncertainties in quadrature (law of propagation of uncertainty); expanded uncertainty with a coverage factor of 2 for a level of confidence of about 95 %.

    listed
  77. [79]

    An Introduction to Error Analysis, 2nd edition (opens in a new tab)

    John R. Taylor · University Science Books, 1997. ISBN 978-0-935702-42-2

    Propagation of small relative errors for products and powers (the factor 2 on the period).

    listed
  78. [80]

    World Geodetic System (1984) (opens in a new tab)

    AHRS (Attitude and Heading Reference Systems) documentation, version 0.4.0

    Somigliana closed form for normal gravity; height correction. Constants re-derived here from the four WGS84 defining parameters.

    read
  79. [81]

    International Gravity Formula (opens in a new tab)

    AHRS documentation

    1980 series coefficients; cites Moritz (1980) and Hinze et al. (2013).

    read
  80. [82]

    Department of Defense World Geodetic System 1984 — Its Definition and Relationships with Local Geodetic Systems, TR8350.2, 3rd edition (opens in a new tab)

    National Imagery and Mapping Agency, 1997

    The WGS84 normal gravity model (cited by MathWorks' gravitywgs84; the URL is that citing page).

    listed
  81. [83]

    Gravity anomaly (opens in a new tab)

    Wikipedia

    Normal gravity accounts for the whole Earth, corrected for its idealised shape and rotation; anomalies are measured in milligals; the free-air correction is 0.3086 mGal per metre of height.

    read
  82. [84]

    Free-air correction (opens in a new tab)

    SLB Energy Glossary

    The free-air correction is 0.3086 mGal/m (0.09406 mGal/ft) of height.

    read
  83. [85]

    Time spent within one angle step of a zero crossing and of a peak

    F9.05, checked against a MuJoCo RK4 swing.

    derived
  84. [86]

    ISO 13528 En Score (Dataplot Reference Manual) (opens in a new tab)

    NIST Information Technology Laboratory

    Cites ISO 13528:2005, pp. 27–28

    The En score divides a difference by the root-sum-square of the two expanded uncertainties; with coverage factor 2, a critical value of 1 matches a z-score of 2, a warning signal.

    read
  85. [87]

    Standard gravity (opens in a new tab)

    Wikipedia

    Standard gravity is the defined constant 9.80665 m/s², set by the 3rd CGPM in 1901 and originally based on free fall at sea level at 45° latitude; actual gravity varies with place.

    read
  86. [88]

    How to Size a Power Supply for a Servo Drive (opens in a new tab)

    ADVANCED Motion Controls, 2026

    Every deceleration drives the load’s kinetic energy back through the drive onto the DC bus; with nowhere to go, the bus voltage rises until the drive faults on overvoltage. An unregulated supply is not built to sink reverse current; a shunt regulator can clamp the bus.

    read
  87. [89]

    Feedback Systems: An Introduction for Scientists and Engineers, 2nd edition (opens in a new tab)

    Karl Johan Åström, Richard M. Murray · Princeton University Press, 2021. ISBN 978-0-691-19398-4. Free online with the publisher’s permission (the authors’ July 2020 PDFs)

    Ch. 7 State Feedback; Ch. 8 Output Feedback (observability, state estimation, Kalman filtering); Ch. 11 PID Control

    The complete book and its chapters are available as PDFs from the authors’ page, with the publisher’s permission; the page notes the site has moved to fbsbook.org. Chapter titles as listed there.

    read
  88. [90]

    Understanding Constant Voltage (CV) and Constant Current (CC) Modes in Regulated Power Supplies (opens in a new tab)

    B&K Precision, technical note, 5 June 2025

    When the load would draw more than the current limit, the supply switches from CV to CC, holds the current at the limit and reduces the voltage as needed.

    read
  89. [91]

    Appearances can be deceiving: Instructor fluency increases perceptions of learning without increasing actual learning (opens in a new tab)

    Shana K. Carpenter, Miko M. Wilford, Nate Kornell, Kellie M. Mullaney · Psychonomic Bulletin & Review (2013), doi:10.3758/s13423-013-0442-z; summarised by the BPS Research Digest

    After a one-minute video, students who watched a fluent lecturer predicted they would do better on a test than those who watched a disfluent one; both did equally well. (Read from the BPS summary.)

    read
  90. [92]

    ClangFormat (opens in a new tab)

    Clang documentation, LLVM 18

    Command-line options: --dry-run, --Werror

    --dry-run reports formatting changes without making them; --Werror turns those reports into errors. Read from llvm-project at llvmorg-18.1.8.

    read
  91. [93]

    Clang-Format Style Options (opens in a new tab)

    Clang documentation, LLVM 18

    With -style=file, clang-format uses the .clang-format file in the closest parent directory of each input file. Read from llvm-project at llvmorg-18.1.8.

    read
  92. [94]

    Working Draft, Standard for Programming Language C++ (N4861), Exception handling (opens in a new tab)

    ISO/IEC JTC1/SC22/WG21, April 2020 (the C++20 working draft)

    [except.ctor] (stack unwinding); [except.handle] (no handler found)

    As control passes from a throw to a handler, automatic objects are destroyed (stack unwinding). If no matching handler is found, std::terminate is called, and whether the stack is unwound first is implementation-defined.

    read
  93. [95]

    Working Draft, Standard for Programming Language C++ (N4861), Language support library (opens in a new tab)

    ISO/IEC JTC1/SC22/WG21, April 2020 (the C++20 working draft)

    [support.start.term] (exit, abort)

    Objects with automatic storage duration are not destroyed as a result of calling exit(); abort() terminates the program without executing destructors.

    read
  94. [96]

    Learning from failure: a meta-analysis of the empirical studies (opens in a new tab)

    A. Darabi, T. L. Arrington, E. Sayilir · Educational Technology Research and Development 66, 1101–1118 (2018)

    Of 187 publications, 62 were relevant, and only 12 used experimental designs and reported statistics suitable for meta-analysis, all from productive-failure and failure-driven-memory research; together they showed a moderately positive effect of learning from failure. (Abstract read.)

    read
  95. [97]

    Stalled and spinning motor on a current-limited supply

    The illustrative motor behind module 08’s braking check (K = 0.1 N·m/A, R = 10 Ω, L = 1 mH): stall current and power from Ohm’s law, and a time-stepped spin-up from rest on a voltage source whose current is clamped at the limit, recording the speed at which the clamp releases.

    derived
  96. [98]

    Measured order of MuJoCo’s Euler and RK4 (tools/robotics/verify.py)

    The running example released from 30°: angle after 2 s at steps of 4, 2 and 1 ms, against an RK4 reference at 10 µs (Euler from 2 to 1 ms, RK4 from 4 to 2 ms), and for Euler also from the differences of the three runs with no reference. Checks: convergence_orders.

    derived
  97. [99]

    Module 07 worked example (tools/robotics/verify.py)

    Twenty seconds of free swing of the running example from 5°: explicit Euler coded by hand (and on the linearised pendulum), MuJoCo’s Euler and RK4, at 2, 1 and 0.5 ms; Euler’s band from the energy at every step, the other figures from the state at the end; compared with F7.07, F7.09 and F7.10. From 30°, explicit Euler and MuJoCo’s Euler at 2 ms. The page’s two C++ update loops are compiled and run as printed, and the semi-implicit one matches MuJoCo’s Euler. Checks: integration_example.

    derived
  98. [100]

    Compiled and run checks for module 05 (tools/robotics/verify.py)

    Module 05’s checks in tools/robotics/verify.py: MuJoCo 3.17.0 behaviour (the step loop and its split under every integrator, energy timing including RK4’s stages and energy sensors, joint sizes, angle units, default density, joint and actuator armature, determinism); the worked example’s two XML models compiled and read back field by field and with mj_printFormattedModel; its GoogleTest, extracted from the page, compiled against the C library from the same release and run against both models and a warning case; mj_loadXML probed with a clean model, one with a compiler warning and one that fails; and five of the sheet’s six C++ entries (F5.05, F5.06, F5.10–F5.12) compiled with -Wconversion -Wsign-conversion -Werror.

    derived
  99. [101]

    Improving students' learning with effective learning techniques: Promising directions from cognitive and educational psychology (opens in a new tab)

    John Dunlosky, Katherine A. Rawson, Elizabeth J. Marsh, Mitchell J. Nathan, Daniel T. Willingham · Psychological Science in the Public Interest 14(1), 2013; summarised in an APS press release

    Of ten techniques reviewed, practice testing and distributed practice were rated high utility; summarisation, highlighting and rereading were among those rated low. (Read from the APS release.)

    read
  100. [102]

    The Character of Physical Law: Seeking New Laws (opens in a new tab)

    Richard P. Feynman · Messenger Lectures, Cornell University, 1964 (BBC film); streamed by Caltech

    The series' closing lecture in the book's order. The Caltech page lists the lectures in its own order.

    The lecture on how a guessed law is tested by computing its consequences and comparing them with experiment.

    listed
  101. [103]

    Physical Pendulum: Period Derivation and Demonstration using Calculus (opens in a new tab)

    Flipping Physics (video, 14:52)

    Derives the angular frequency and period of a physical pendulum, then checks the prediction with a demonstration.

    listed
  102. [104]

    Back to Basics: Move Semantics (part 2 of 2) (opens in a new tab)

    Klaus Iglberger · CppCon 2019, CppCon YouTube channel

    Forwarding references and perfect forwarding. Topics confirmed from the official slides; video id from a listing of the CppCon channel.

    listed
  103. [105]

    Kalman and Bayesian Filters in Python (opens in a new tab)

    Roger R. Labbe Jr. · GitHub (Jupyter notebooks; text CC BY 4.0, code MIT)

    A free book in Jupyter notebooks that focuses on building intuition and experience rather than formal proofs, from the g-h filter through one-dimensional and multivariate Kalman filters to extended and unscented filters and particle filters; all exercises include solutions.

    read
  104. [106]

    Modern Robotics — Mechanics, Planning, and Control, Chapter 11: Robot Control (opens in a new tab)

    Kevin M. Lynch, Frank C. Park · Cambridge University Press, 2017. Free preprint for personal use at the book site

    Ch. 11 (p. 405): §11.1 Control System Overview (p. 406); §11.2.2 Linear Error Dynamics (p. 408); §11.4.1 Motion Control of a Single Joint (p. 423); §11.4.2 Motion Control of a Multi-joint Robot (p. 431)

    Chapter and section titles from the preprint’s table of contents. The book’s Chapter 1 preview of Chapter 11 describes controllers “such as computed torque control, that combine approximate dynamic modeling with feedback control.” The body of §11.4 was not read for this page.

    read
  105. [107]

    Understanding Kalman Filters (MATLAB Tech Talks, 7 videos) (opens in a new tab)

    MathWorks

    Seven videos of 5 to 9 minutes: Why Use Kalman Filters?; State Observers; An Optimal State Estimator; An Optimal State Estimator Algorithm; Nonlinear State Estimators; and two on using Kalman filters in Simulink. Titles read from the series page; videos not watched for this page.

    read
  106. [108]

    Understanding PID Control (MATLAB Tech Talks, 7 videos) (opens in a new tab)

    MathWorks

    Seven videos of 10 to 14 minutes: What Is PID Control?; Anti-windup for PID control; Expanding Beyond a Simple Derivative; A PID Tuning Guide; 3 Ways to Build a Model; Manual and Automatic Tuning Methods; Important PID Concepts. Titles read from the series page; videos not watched for this page.

    read
  107. [109]

    Worked and Faded Examples (opens in a new tab)

    MIT Open Learning, research-based learning findings

    Novices learn more from studying step-by-step solutions than from solving problems, provided they self-explain them; experts benefit more from solving; support should be faded as expertise grows.

    read
  108. [110]

    Euler, ODE1 (opens in a new tab)

    Cleve Moler · MIT OpenCourseWare RES.18-009, Learn Differential Equations: Up Close with Gilbert Strang and Cleve Moler (2015)

    Introduces numerical methods for ODEs through Euler’s method (MATLAB’s ODE1), with exponential growth and compound interest as examples. The first of the 12 videos in the OCW gallery “Solving ODEs in MATLAB”. Video ID and description from the OCW page; not watched for this page.

    listed
  109. [111]

    Classical Runge-Kutta, ODE4 (opens in a new tab)

    Cleve Moler · MIT OpenCourseWare RES.18-009, Learn Differential Equations: Up Close with Gilbert Strang and Cleve Moler (2015)

    The classical Runge–Kutta method, described as the most widely used numerical method for ODEs; its drawback is the lack of an error estimate. Video ID and description from the OCW page; not watched for this page.

    listed
  110. [112]

    Order, Naming Conventions (opens in a new tab)

    Cleve Moler · MIT OpenCourseWare RES.18-009, Learn Differential Equations: Up Close with Gilbert Strang and Cleve Moler (2015)

    OCW page description (video ID 6O9D6am_RK4)

    “A method is said to have order p if cutting the step size in half reduces the error in one step by a factor of two to the power p+1.” Read from the OCW page’s description; the video itself was not watched for this page.

    read
  111. [113]

    Modern Robotics, Chapter 11.1: Control System Overview (opens in a new tab)

    Kevin M. Lynch · Northwestern University, Modern Robotics video series (YouTube)

    The book’s overview video for chapter 11, Robot Control. Linked from the book site’s chapter 11 video list.

    listed
  112. [114]

    Modern Robotics, Chapter 11.2.2: Linear Error Dynamics (opens in a new tab)

    Kevin M. Lynch · Northwestern University, Modern Robotics video series (YouTube)

    The book’s video on linear error dynamics (§11.2.2). Linked from the book site’s chapter 11 video list.

    listed
  113. [115]

    Modern Robotics, Chapter 11.2.2.2: Second-Order Error Dynamics (opens in a new tab)

    Kevin M. Lynch · Northwestern University, Modern Robotics video series (YouTube)

    The book’s video on second-order error dynamics (§11.2.2.2). Linked from the book site’s chapter 11 video list.

    listed
  114. [116]

    Modern Robotics, Chapter 11.4: Motion Control with Torque or Force Inputs (Part 1 of 3) (opens in a new tab)

    Kevin M. Lynch · Northwestern University, Modern Robotics video series (YouTube)

    The first of three videos on §11.4, motion control with torque or force inputs. Linked from the book site’s chapter 11 video list.

    listed
  115. [117]

    Modern Robotics, Chapter 8.1.3: Understanding the Mass Matrix (opens in a new tab)

    Kevin M. Lynch · Northwestern University, Modern Robotics video series (YouTube)

    The book’s own short video on the mass matrix M(θ). Linked from the book site’s chapter 8 video list.

    listed
  116. [118]

    Modern Robotics, Chapter 8.9: Actuation, Gearing, and Friction (opens in a new tab)

    Kevin M. Lynch · Northwestern University, Modern Robotics video series (YouTube)

    The book’s own video for §8.9: motors, gearing, apparent (reflected) inertia and friction models. Linked from the book site’s chapter 8 video list.

    listed
  117. [119]

    MuJoCo Programming chapter, Introduction (3.17.0) (opens in a new tab)

    Google DeepMind

    Version check: mjVERSION_HEADER and mj_version()

    Recommends comparing the header's mjVERSION_HEADER with the library's mj_version() at run time. Read from the 3.17.0 source of the docs.

    read
  118. [120]

    MuJoCo Python bindings (3.17.0) (opens in a new tab)

    Google DeepMind

    introduction; Structs; Functions

    The Python API is consistent with the underlying C API; struct fields give access to MuJoCo’s raw memory without copying, so mj_step changes them in place and values to be kept must be copied; MuJoCo functions keep their C names. Read from the 3.17.0 source of the docs.

    read
  119. [121]

    mj_deleteData, src/engine/engine_io.c (MuJoCo 3.17.0) (opens in a new tab)

    Google DeepMind, GitHub

    Freeing mjData never reads the mjModel (so destruction order is a discipline, not a crash, for MuJoCo specifically).

    read
  120. [122]

    MuJoCo tutorial notebook (Python, runs in Colab) (opens in a new tab)

    Google DeepMind, GitHub

    The official hands-on introduction: MJCF, mjModel and mjData, named access, simulation and rendering, from Python. Its “Open in Colab” link runs the latest release, not necessarily 3.17.0.

    read
  121. [123]

    Saying the wrong thing: Improving learning with multimedia by including misconceptions (opens in a new tab)

    Derek A. Muller, J. Bewes, Manjula D. Sharma, Peter Reimann · Journal of Computer Assisted Learning 24(2), 144–155 (2008)

    A peer-reviewed study from the same research programme on misconception videos. Citation from Muller’s publications page and the journal record; not read for this page.

    listed
  122. [124]

    Helll-ooo! Watching Videos Does Not Necessarily Lead to Learning (opens in a new tab)

    Cathie Norris, Elliot Soloway · THE Journal (21st Century Learning), 6 May 2015

    Reports Derek Muller’s PhD research. Students scored about 6 of 26 before instruction and “did abysmally, again” after a clear expository physics video, though they rated it clear and felt confident in their answers. After a video in which a student voiced misconceptions and a teacher corrected them, scores roughly doubled to almost 12 of 26, and students reported more mental effort.

    read
  123. [125]

    Verification and validation in computational fluid dynamics (opens in a new tab)

    William L. Oberkampf, Timothy G. Trucano · Progress in Aerospace Sciences 38(3), 209–272 (2002). Sandia report SAND2002-0529, doi:10.2172/793406

    §2.1 (AIAA definitions of verification and validation); §1.1 and §2.3 (verification as a mathematics issue, after Roache)

    Verification: the implementation accurately represents the conceptual model and its solution. Validation: the degree to which the model represents the real world for its intended use. 'Verification does not address whether the conceptual model has any relationship to the real world.'

    read
  124. [126]

    Lecture 11: Mass Moment of Inertia of Rigid Bodies (opens in a new tab)

    J. Kim Vandiver · MIT OpenCourseWare, 2.003SC Engineering Dynamics, Fall 2011

    Lecture video covering the inertia matrix, principal axes, a disk example and the parallel-axis theorem (topics confirmed from the course page).

    listed
  125. [127]

    Estimation of natural frequencies and damping ratios from measured response: the logarithmic decrement (opens in a new tab)

    J. Kim Vandiver · MIT OpenCourseWare, 2.003SC Engineering Dynamics, Fall 2011 (a chapter of Lecture 19)

    Lecture chapter on estimating natural frequency and damping ratio from a measured free decay.

    listed
  126. [128]

    Lecture 20: Linear System Modeling a Single Degree of Freedom Oscillator (opens in a new tab)

    J. Kim Vandiver · MIT OpenCourseWare, 2.003SC Engineering Dynamics, Fall 2011

    Lecture video on damped free response and on determining the damping ratio by experiment (topics confirmed from the lecture page's description).

    listed
  127. [129]

    University Physics Volume 1, §15.1 Simple Harmonic Motion (opens in a new tab)

    William Moebs, Samuel J. Ling, Jeff Sanny · OpenStax, 2016. CC BY 4.0

    Eq. 15.1 (f = 1/T); angular frequency ω = 2π/T = 2πf (unnumbered)

    Frequency in hertz versus angular frequency in inverse seconds (radians per second), and the factor 2π between them.

    read
  128. [130]

    Structuring the transition from example study to problem solving in cognitive skill acquisition: a cognitive load perspective (opens in a new tab)

    Alexander Renkl, Robert K. Atkinson · Educational Psychologist 38(1), 15–22 (2003)

    Proposes fading, in which problem-solving elements are successively integrated into example study until learners solve problems on their own. The link is the research record of a 2016 reprint; its abstract was read, the 2003 article itself was not.

    listed
  129. [131]

    The pretesting effect: Do unsuccessful retrieval attempts enhance learning? (opens in a new tab)

    Lindsey E. Richland, Nate Kornell, Liche Sean Kao · Journal of Experimental Psychology: Applied 15(3), 243–257 (2009). doi:10.1037/a0016496

    Taking a test before studying, even one mostly failed (5–22 % correct), improved later recall of the pretested information more than spending the same time studying; untested information did not differ from the extended-study condition. The material was a factual text on vision.

    read
  130. [132]

    Test-enhanced learning: Taking memory tests improves long-term retention (opens in a new tab)

    Henry L. Roediger III, Jeffrey D. Karpicke · Psychological Science 17(3), 249–255 (2006). doi:10.1111/j.1467-9280.2006.01693.x

    After 5 minutes, repeated studying beat repeated testing; after 2 days or 1 week, prior testing produced substantially better retention than studying, although studying raised confidence more.

    read
  131. [133]

    What is the difference between a Logic Analyzer and an Oscilloscope? (opens in a new tab)

    Joe Garrison · Saleae blog, 21 December 2017

    Logic analyzers are best for digital signals and protocols (I²C, SPI, serial), recording ones and zeros over time; oscilloscopes are best for analog signals, tracking voltage and how it changes.

    read
  132. [134]

    Can These Products Replace an Oscilloscope? (opens in a new tab)

    Saleae support

    Saleae devices are logic analyzers with analog logging, of lower bandwidth than oscilloscopes and with fixed input range; a scope is still needed for signal integrity, high-bandwidth analog, small voltages at high resolution and voltages outside their range.

    read
  133. [135]

    Sanitize your C++ code (opens in a new tab)

    Kostya Serebryany · CppCon 2014; posted on isocpp.org

    The sanitizers explained by one of their authors: AddressSanitizer, ThreadSanitizer, MemorySanitizer and UndefinedBehaviorSanitizer, how they work and how they are deployed.

    listed
  134. [136]

    SPD1000X Series Programmable Linear DC Power Supply, data sheet (DataSheet-2021.04) (opens in a new tab)

    Siglent Technologies, April 2021 (copy hosted by SMU Physics)

    SPD1305X: 30 V / 5 A, up to 150 W; constant-voltage and constant-current modes; output short-circuit and overload protection.

    read
  135. [137]

    SPD1305X Programmable Linear DC Power Supply (opens in a new tab)

    Siglent Technologies NA, product page

    Output 0–30 V, 0–5 A, 150 W; a programmable linear supply. (The page’s feature list also shows 16 V / 8 A figures that belong to another model.)

    read
  136. [138]

    std::sin, std::sinf, std::sinl (opens in a new tab)

    cppreference.com (2024-06-10), as packaged in the stdman manual pages

    The C++ standard library's sine takes its argument in radians.

    read
  137. [139]

    The use of worked examples as a substitute for problem solving in learning algebra (opens in a new tab)

    John Sweller, Graham A. Cooper · Cognition and Instruction 2(1), 59–89 (1985). doi:10.1207/s1532690xci0201_3

    Five experiments in algebra. Experiment 1 compared levels of expertise; in Experiments 2–5, worked examples took less time to process than conventional problems, and later problems of the same structure were solved faster and with fewer errors. Abstract read from a reproduction of the paper’s record (synapsesocial.com); DOI 10.1207/s1532690xci0201_3.

    read
  138. [140]

    Underactuated Robotics, Chapter 2: The Simple Pendulum (opens in a new tab)

    Russ Tedrake · MIT course notes, Spring 2024 (online)

    Course notes on the pendulum’s dynamics, with damping and a control torque, the torque-limited pendulum, and energy-shaping feedback control.

    read
  139. [141]

    Differential equations, studying the unsolvable (DE1) (opens in a new tab)

    Grant Sanderson · 3Blue1Brown, 31 March 2019

    An animated introduction to differential equations built around the pendulum equation.

    listed
  140. [142]

    DRV8833 Dual H-Bridge Motor Driver, data sheet (SLVSAR1E) (opens in a new tab)

    Texas Instruments, 2011, revised 2015

    §7.3.2 Bridge Control and Decay Modes, Table 1 (H-Bridge Logic); §7.3.5.3 Undervoltage Lockout

    A driver’s two “off” states: coast (outputs high-impedance; in fast decay the recirculation current flows through the body diodes) and brake (both outputs low, which shorts the winding). Below the undervoltage threshold (VM < 2.5 V) all circuitry in the device is disabled.

    read
  141. [143]

    DRV8842 data sheet, Power Supply Recommendations (SLVSAB8G) (opens in a new tab)

    Texas Instruments, 2010, revised 2016

    §9.1 Bulk Capacitance Sizing

    Bulk capacitors should be rated above the operating voltage to allow for cases when the motor transfers energy to the supply; without enough bulk capacitance the supply voltage moves with the motor’s current demands and dumps.

    read
  142. [144]

    C++ Weekly, Episode 3: Intro to clang-tidy (opens in a new tab)

    Jason Turner · C++ Weekly (YouTube); announced on isocpp.org, 28 March 2016

    Basic use of clang-tidy, including applying its automatic fixes.

    listed
  143. [145]

    C++ Weekly, Episode 84: C++ Sanitizers (opens in a new tab)

    Jason Turner · C++ Weekly (YouTube); announced on isocpp.org, 1 November 2017

    A short episode on the runtime sanitizers in GCC and Clang and what each detects.

    listed
  144. [146]

    Stop Categories (UR20/UR30 user manual) (opens in a new tab)

    Universal Robots

    Stop categories as defined in IEC 60204-1: 0, stop by immediate removal of power; 1, controlled stop, then power removed; 2, stop with power maintained to the drives.

    read
  145. [147]

    Khan Academy and the Effectiveness of Science Videos (opens in a new tab)

    Derek Muller · Veritasium (YouTube), 17 March 2011

    Muller on why a clear science video can leave viewers’ misconceptions in place. Listed from the NUS Physics Society’s video archive, not watched for this page; Muller’s research on the same question is reported in THE Journal, 6 May 2015.

    listed
  146. [148]

    Cogging torque (opens in a new tab)

    Wikipedia

    Cogging is the interaction between the rotor magnets and the stator slots; it is a detent (no-current) torque, especially prominent at low speed.

    read
  147. [149]

    Worked-example effect (opens in a new tab)

    Wikipedia

    The worked-example effect, first described from a cognitive-load perspective by Sweller and Cooper (1985); worked examples lose effectiveness as expertise grows (expertise reversal), which fading addresses.

    read
  148. [150]

    Power Supplies Can Absorb Power, Too (opens in a new tab)

    Bob Zollo · Electronic Design, 1 February 2018

    In most power supplies, some provision is made to discharge the output capacitor: a bleed resistor or an active down-programmer, the latter typically limited to about 10 % of rated output current. A supply that can also sink current is called two-quadrant. A device under test can itself be an energy generator.

    read