<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://watonomous.github.io/humanoid-docs/blog</id>
    <title>WATonomous Humanoid Team Blog</title>
    <updated>2026-08-05T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://watonomous.github.io/humanoid-docs/blog"/>
    <subtitle>WATonomous Humanoid Team Blog</subtitle>
    <icon>https://watonomous.github.io/humanoid-docs/img/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[Inverse Kinematics: Arm & Hand]]></title>
        <id>https://watonomous.github.io/humanoid-docs/blog/ik-deep-dive</id>
        <link href="https://watonomous.github.io/humanoid-docs/blog/ik-deep-dive"/>
        <updated>2026-08-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[How do you tell a robot arm "put your hand right here," or a robot hand "put your fingertip right here," and have it actually figure out the joint angles to make that happen? That's inverse kinematics, and it's what drives both the bimanual arm setup and the individual hand.]]></summary>
        <content type="html"><![CDATA[<p>How do you tell a robot arm "put your hand right here," or a robot hand "put your fingertip right here," and have it actually figure out the joint angles to make that happen? That's inverse kinematics, and it's what drives both the bimanual arm setup and the individual hand.</p>
<video width="600" controls=""><source src="/humanoid-docs/img/humanoid/videos/ik-bimanual-arm.mp4" type="video/mp4"></video>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="forward-vs-inverse">Forward vs. inverse<a href="https://watonomous.github.io/humanoid-docs/blog/ik-deep-dive#forward-vs-inverse" class="hash-link" aria-label="Direct link to Forward vs. inverse" title="Direct link to Forward vs. inverse" translate="no">​</a></h2>
<p>Forward kinematics is the easy direction: given a set of joint angles, figure out where the end effector ends up. Just chain the transforms down the chain — this joint rotates this much, that joint rotates that much, tip lands here. Mechanical, no ambiguity, one answer.</p>
<p>Inverse kinematics is the direction we actually want, and it's the hard one: given a target position, figure out what joint angles get you there. With enough joints, there's no clean formula for this — you can't just "solve for q." So instead of solving it directly, we solve it iteratively: start from wherever the arm or hand currently is, and nudge the joints a little bit at a time until it gets close enough to the target.</p>
<p>Both of the IK systems on the robot — the bimanual arm and the hand — work this way. Same core technique, damped least squares (DLS), used in two different setups depending on what's being targeted.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="two-arms-two-independent-chains">Two arms, two independent chains<a href="https://watonomous.github.io/humanoid-docs/blog/ik-deep-dive#two-arms-two-independent-chains" class="hash-link" aria-label="Direct link to Two arms, two independent chains" title="Direct link to Two arms, two independent chains" translate="no">​</a></h2>
<p>For the bimanual arm setup (video above), a cube in the scene is the target — move the cube, and the arm's 6 joints follow to keep the gripper tip on it. This one runs on Isaac Lab's built-in <code>DifferentialIKController</code> with <code>ik_method="dls"</code>, so we get damped least squares for free without writing our own solver.</p>
<p>That works cleanly here because each arm only ever has one target: its own gripper tip. And since the left arm's 6 joints and the right arm's 6 joints don't overlap — two fully independent kinematic chains off the torso — there's zero coupling between them. Each arm gets its own controller instance, chasing its own target, completely unaware the other arm exists.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="five-fingertips-one-shared-chain">Five fingertips, one shared chain<a href="https://watonomous.github.io/humanoid-docs/blog/ik-deep-dive#five-fingertips-one-shared-chain" class="hash-link" aria-label="Direct link to Five fingertips, one shared chain" title="Direct link to Five fingertips, one shared chain" translate="no">​</a></h2>
<video width="600" controls=""><source src="https://github.com/user-attachments/assets/02b19410-c39e-403a-9bea-164c5141f61f" type="video/mp4"></video>
<p>The hand can't get away with the same trick. It's a 6 DOF arm plus a 15 DOF hand — 21 degrees of freedom total — driving 5 fingertips at once, and all 5 of those fingertips share the same upstream arm joints. A target for one fingertip and a target for another aren't independent: moving the arm to help one finger reach its target shifts where every other finger ends up too.</p>
<p>A single-target controller like <code>DifferentialIKController</code> has no way to solve that — it only ever sees one Jacobian block for one body. So instead, <code>fingertip_ik.py</code> is a hand-rolled solver that stacks all 5 fingertip Jacobians into one system and solves for all 21 joints jointly, so the shared arm joints get moved in a way that's good for all 5 targets at once, not just whichever one happened to go first.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-damped-least-squares">Why damped least squares<a href="https://watonomous.github.io/humanoid-docs/blog/ik-deep-dive#why-damped-least-squares" class="hash-link" aria-label="Direct link to Why damped least squares" title="Direct link to Why damped least squares" translate="no">​</a></h3>
<p>With 21 joints and only 15 position constraints (5 fingertips × 3D each), the naive approach — just invert the Jacobian and solve directly — runs into trouble near certain poses: the Jacobian gets close to singular, and a plain inverse tries to divide by something close to zero. That means huge, unstable joint jumps right when the hand is near a tricky configuration.</p>
<p>Damped least squares fixes this by adding a small penalty on how big the joint step is allowed to be, instead of solving the system exactly. That penalty (the damping term) keeps the solution well-behaved even when the Jacobian is near-singular, at the cost of moving a bit more cautiously.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-loop">The loop<a href="https://watonomous.github.io/humanoid-docs/blog/ik-deep-dive#the-loop" class="hash-link" aria-label="Direct link to The loop" title="Direct link to The loop" translate="no">​</a></h3>
<p>Each iteration does basically the same four things:</p>
<ol>
<li class=""><strong>Where are we now?</strong> Run forward kinematics to get the current fingertip positions.</li>
<li class=""><strong>How far off are we?</strong> For every fingertip with a target, compute the error vector — target position minus current position — and stack all of them into one big error vector <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">e</mi></mrow><annotation encoding="application/x-tex">\mathbf{e}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4444em"></span><span class="mord mathbf">e</span></span></span></span>.</li>
<li class=""><strong>Which way do we move?</strong> Build the Jacobian <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">J</mi></mrow><annotation encoding="application/x-tex">\mathbf{J}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6861em"></span><span class="mord mathbf">J</span></span></span></span> — it maps small joint changes to small fingertip movements — and solve the damped least squares problem for the joint step <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Δ</mi><mi mathvariant="bold">q</mi></mrow><annotation encoding="application/x-tex">\Delta\mathbf{q}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em"></span><span class="mord">Δ</span><span class="mord mathbf">q</span></span></span></span>:</li>
</ol>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mo fence="true" stretchy="true" minsize="1.2em" maxsize="1.2em">(</mo><msup><mi mathvariant="bold">J</mi><mi mathvariant="sans-serif">T</mi></msup><mi mathvariant="bold">J</mi><mo>+</mo><mi>λ</mi><mi mathvariant="bold">I</mi><mo fence="true" stretchy="true" minsize="1.2em" maxsize="1.2em">)</mo><mtext> </mtext><mi mathvariant="normal">Δ</mi><mi mathvariant="bold">q</mi><mo>=</mo><msup><mi mathvariant="bold">J</mi><mi mathvariant="sans-serif">T</mi></msup><mi mathvariant="bold">e</mi></mrow><annotation encoding="application/x-tex">\bigl(\mathbf{J}^{\mathsf T}\mathbf{J} + \lambda \mathbf{I}\bigr)\,\Delta\mathbf{q} = \mathbf{J}^{\mathsf T}\mathbf{e}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2491em;vertical-align:-0.35em"></span><span class="mopen"><span class="delimsizing size1">(</span></span><span class="mord"><span class="mord mathbf">J</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathsf mtight">T</span></span></span></span></span></span></span></span></span><span class="mord mathbf">J</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1.2em;vertical-align:-0.35em"></span><span class="mord mathnormal">λ</span><span class="mord mathbf">I</span><span class="mclose"><span class="delimsizing size1">)</span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord">Δ</span><span class="mord mathbf">q</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.8991em"></span><span class="mord"><span class="mord mathbf">J</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8991em"><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathsf mtight">T</span></span></span></span></span></span></span></span></span><span class="mord mathbf">e</span></span></span></span></span>
<ol start="4">
<li class=""><strong>Take the step.</strong> Apply a fraction of that joint step (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="bold">q</mi><mo>←</mo><mi mathvariant="bold">q</mi><mo>+</mo><mi>α</mi><mtext> </mtext><mi mathvariant="normal">Δ</mi><mi mathvariant="bold">q</mi></mrow><annotation encoding="application/x-tex">\mathbf{q} \leftarrow \mathbf{q} + \alpha\,\Delta\mathbf{q}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6389em;vertical-align:-0.1944em"></span><span class="mord mathbf">q</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.1944em"></span><span class="mord mathbf">q</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em"></span><span class="mord mathnormal" style="margin-right:0.0037em">α</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord">Δ</span><span class="mord mathbf">q</span></span></span></span>), clip to joint limits, and repeat.</li>
</ol>
<p>That loop runs until the error drops below a tolerance or it hits a max iteration count — at which point you've got a joint configuration that puts every fingertip where it needs to be, or as close as the hand's geometry allows. The Jacobians and forward kinematics come from MuJoCo, with Isaac Sim handling visualization. Only fingertip position is constrained — orientation is left free — which keeps the problem smaller and the solver faster per iteration.</p>
<p>For the exact algorithm, defaults, and code-level detail, see the <a class="" href="https://watonomous.github.io/humanoid-docs/software">Software &amp; ML docs</a>.</p>]]></content>
        <author>
            <name>Wilson</name>
        </author>
        <category label="Software" term="Software"/>
        <category label="IK" term="IK"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Summer 2026 Progress Update]]></title>
        <id>https://watonomous.github.io/humanoid-docs/blog/s26-term-update</id>
        <link href="https://watonomous.github.io/humanoid-docs/blog/s26-term-update"/>
        <updated>2026-08-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[As the term wraps up, here's where the humanoid team landed this summer — and it's been a big one.]]></summary>
        <content type="html"><![CDATA[<p>As the term wraps up, here's where the humanoid team landed this summer — and it's been a big one.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="this-term">This term<a href="https://watonomous.github.io/humanoid-docs/blog/s26-term-update#this-term" class="hash-link" aria-label="Direct link to This term" title="Direct link to This term" translate="no">​</a></h2>
<ul>
<li class=""><strong>40+ contributing members</strong> — the team grew to one of the largest design teams at UWaterloo, all in a single term.</li>
<li class=""><strong>A functional 7 DOF humanoid arm</strong> — currently working through a motor issue, fix incoming.</li>
<li class=""><strong>A 22 DOF humanoid hand</strong> with fully routed tendons.</li>
<li class=""><strong>A fully designed 12 DOF humanoid leg</strong>, set to be built next term.</li>
<li class="">A full-body humanoid is coming soon, and everything above already exists in simulation for ML training.</li>
<li class="">Renewed partnerships and sponsorship — companies like CubeMars, plus a growing list of people reaching out to learn more about the team.</li>
</ul>
<p>We set our goals for the term in our <a href="https://wiki.watonomous.ca/quest_books/s26_humanoid_quests/" target="_blank" rel="noopener noreferrer" class="">quest book</a> at the start of the summer, and we've far exceeded all of them.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-were-headed">Where we're headed<a href="https://watonomous.github.io/humanoid-docs/blog/s26-term-update#where-were-headed" class="hash-link" aria-label="Direct link to Where we're headed" title="Direct link to Where we're headed" translate="no">​</a></h2>
<p>One-year goal: a humanoid that walks around campus on its own, with arms doing useful work — assembling its own components, folding clothes, that kind of thing.</p>]]></content>
        <author>
            <name>Wilson</name>
        </author>
        <category label="Progress Update" term="Progress Update"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[TVC Rocket: A Technical Deep Dive]]></title>
        <id>https://watonomous.github.io/humanoid-docs/blog/tvc-rocket-deep-dive</id>
        <link href="https://watonomous.github.io/humanoid-docs/blog/tvc-rocket-deep-dive"/>
        <updated>2026-08-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A spinoff from the WATonomous Humanoid team: a thrust-vector-controlled (TVC) rocket. Here's how it works.]]></summary>
        <content type="html"><![CDATA[<p>A spinoff from the WATonomous Humanoid team: a thrust-vector-controlled (TVC) rocket. Here's how it works.</p>
<video width="600" controls=""><source src="/humanoid-docs/img/humanoid/videos/tvc-rocket.mp4" type="video/mp4"></video>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-tvc">What is TVC?<a href="https://watonomous.github.io/humanoid-docs/blog/tvc-rocket-deep-dive#what-is-tvc" class="hash-link" aria-label="Direct link to What is TVC?" title="Direct link to What is TVC?" translate="no">​</a></h2>
<p>Have you ever wondered how NASA or SpaceX control their rocket during flight? For a small model rocket, the most straightforward option is fins — just let the airflow keep the rocket pointed straight. But fins get impractical once you're at large scale: no airflow, no control, and they're just extra drag and weight you're dragging along.</p>
<p>So instead, big rockets use <strong>thrust vector control (TVC)</strong>. The idea is simple: you control where the thrust points, and use the horizontal component of that thrust to generate a torque that controls the rocket's orientation. Tilt the engine a few degrees off-center, and now part of that thrust is pushing sideways instead of straight down — and since it's acting away from the rocket's center of mass, it rotates the rocket. Doesn't matter how fast (or slow) you're going, it still works, which is why it's the go-to for landings too, not just ascent.</p>
<img src="https://watonomous.github.io/humanoid-docs/img/humanoid/rocketry/tvc-diagram.png" alt="TVC gimbal angle and torque diagram" width="500">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="meet-pioneer">Meet Pioneer<a href="https://watonomous.github.io/humanoid-docs/blog/tvc-rocket-deep-dive#meet-pioneer" class="hash-link" aria-label="Direct link to Meet Pioneer" title="Direct link to Meet Pioneer" translate="no">​</a></h2>
<p>The long term goal here is propulsive landing — bringing the rocket back down under its own thrust, SpaceX-style, or eventually even catching it out of the air like Starship's booster does with the tower's "chopsticks." Both of those are really just TVC problems taken further, needing control through a much harder flight regime than ascent.</p>
<p><strong>Pioneer</strong>, the rocket in the video above, only has to nail one thing: ascent. Stable, controlled powered flight. Landing and catching come once that's solid.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-control-algorithm">The control algorithm<a href="https://watonomous.github.io/humanoid-docs/blog/tvc-rocket-deep-dive#the-control-algorithm" class="hash-link" aria-label="Direct link to The control algorithm" title="Direct link to The control algorithm" translate="no">​</a></h2>
<p>So the first thing you're probably wondering is: what's actually driving the gimbal? This is where it gets technically kind of hairy.</p>
<p>Two things are working against us:</p>
<ol>
<li class="">We're using <strong>solid rocket motors</strong> — the impulse is huge the moment it lights, and once it's lit, that's it, you can't throttle it or shut it off.</li>
<li class="">Every launch burns exactly one motor. There's no re-testing on the cheap — if the controller doesn't work, you don't get a redo, you just wasted a motor.</li>
</ol>
<p>Put those together and you get a lot of pressure to have the control method figured out before it ever leaves the ground. The solution we went with is honestly just <strong>PID control</strong>, and it works surprisingly well even under these constraints.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-ping-pong-ball-analogy">The ping-pong ball analogy<a href="https://watonomous.github.io/humanoid-docs/blog/tvc-rocket-deep-dive#the-ping-pong-ball-analogy" class="hash-link" aria-label="Direct link to The ping-pong ball analogy" title="Direct link to The ping-pong ball analogy" translate="no">​</a></h3>
<p>Easiest way to think about PID: balancing a ping-pong ball on a racket, trying to keep it centered.</p>
<ul>
<li class="">
<p><strong>P (Proportional)</strong> — as the ball gets further from center, you'd naturally tilt the racket more to bring it back. That's proportional control: you tilt based on how far off-center the ball currently is. Bigger offset, bigger tilt.</p>
<p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>u</mi><mi>P</mi></msub><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo><mo>=</mo><msub><mi>K</mi><mi>p</mi></msub><mtext> </mtext><mi>e</mi><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">u_P(t) = K_p\, e(t)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal">u</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">P</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1.0361em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">K</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">p</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">e</span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span></span></span></span></p>
</li>
<li class="">
<p><strong>D (Derivative)</strong> — if the goal is to have the ball sitting still at the center, position alone isn't enough. You also watch how fast it's moving toward the center, and pre-emptively tilt against that motion so it slows down and settles right at the center instead of flying past it.</p>
<p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>u</mi><mi>D</mi></msub><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo><mo>=</mo><msub><mi>K</mi><mi>d</mi></msub><mfrac><mrow><mi>d</mi><mi>e</mi><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">u_D(t) = K_d \frac{de(t)}{dt}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal">u</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0278em">D</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1.355em;vertical-align:-0.345em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">K</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">d</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.01em"><span style="top:-2.655em"><span class="pstrut" style="height:3em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em"><span class="pstrut" style="height:3em"></span><span class="frac-line" style="border-bottom-width:0.04em"></span></span><span style="top:-3.485em"><span class="pstrut" style="height:3em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">e</span><span class="mopen mtight">(</span><span class="mord mathnormal mtight">t</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></p>
</li>
<li class="">
<p><strong>I (Integral)</strong> — if the ball keeps drifting the same way over time (say your racket's slightly tilted to begin with), you accumulate that error and correct for the persistent bias — something P alone can't fix.</p>
<p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>u</mi><mi>I</mi></msub><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo><mo>=</mo><msub><mi>K</mi><mi>i</mi></msub><msubsup><mo>∫</mo><mn>0</mn><mi>t</mi></msubsup><mi>e</mi><mo stretchy="false">(</mo><mi>τ</mi><mo stretchy="false">)</mo><mtext> </mtext><mi>d</mi><mi>τ</mi></mrow><annotation encoding="application/x-tex">u_I(t) = K_i \int_0^t e(\tau)\, d\tau</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal">u</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0785em">I</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1.3443em;vertical-align:-0.3558em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">K</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop"><span class="mop op-symbol small-op" style="margin-right:0.1945em;position:relative;top:-0.0006em">∫</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.9885em"><span style="top:-2.3442em;margin-left:-0.1945em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span><span style="top:-3.2579em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">t</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3558em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">e</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.1132em">τ</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">d</span><span class="mord mathnormal" style="margin-right:0.1132em">τ</span></span></span></span></p>
</li>
</ul>
<p>Worth noting: not every real controller actually uses all three terms. A lot of actuator-driven systems run <strong>PD</strong> instead of full PID — the integral term can cause "windup" issues once the actuator saturates (maxes out), where the buildup causes a big overshoot once it un-saturates. For a fast gimbal that's often close to its deflection limits, that tradeoff usually isn't worth it, so some setups skip the I term entirely.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="applying-it-to-the-rocket">Applying it to the rocket<a href="https://watonomous.github.io/humanoid-docs/blog/tvc-rocket-deep-dive#applying-it-to-the-rocket" class="hash-link" aria-label="Direct link to Applying it to the rocket" title="Direct link to Applying it to the rocket" translate="no">​</a></h3>
<p>Same principle, just applied to the rocket instead of a ball. Instead of position, the error term is the gap between desired and actual pitch/yaw angle:</p>
<p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>e</mi><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo><mo>=</mo><msub><mi>θ</mi><mrow><mi>d</mi><mi>e</mi><mi>s</mi><mi>i</mi><mi>r</mi><mi>e</mi><mi>d</mi></mrow></msub><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo><mo>−</mo><msub><mi>θ</mi><mrow><mi>a</mi><mi>c</mi><mi>t</mi><mi>u</mi><mi>a</mi><mi>l</mi></mrow></msub><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">e(t) = \theta_{desired}(t) - \theta_{actual}(t)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal">e</span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0278em">θ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0278em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">es</span><span class="mord mathnormal mtight">i</span><span class="mord mathnormal mtight" style="margin-right:0.0278em">r</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">d</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0278em">θ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0278em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">a</span><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">t</span><span class="mord mathnormal mtight">u</span><span class="mord mathnormal mtight">a</span><span class="mord mathnormal mtight" style="margin-right:0.0197em">l</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span></span></span></span></p>
<p>The PID controller turns that error into a commanded gimbal deflection angle <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>δ</mi><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\delta(t)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0379em">δ</span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span></span></span></span>:</p>
<p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>δ</mi><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo><mo>=</mo><msub><mi>K</mi><mi>p</mi></msub><mtext> </mtext><mi>e</mi><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo><mo>+</mo><msub><mi>K</mi><mi>i</mi></msub><msubsup><mo>∫</mo><mn>0</mn><mi>t</mi></msubsup><mi>e</mi><mo stretchy="false">(</mo><mi>τ</mi><mo stretchy="false">)</mo><mtext> </mtext><mi>d</mi><mi>τ</mi><mo>+</mo><msub><mi>K</mi><mi>d</mi></msub><mfrac><mrow><mi>d</mi><mi>e</mi><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">\delta(t) = K_p\, e(t) + K_i \int_0^t e(\tau)\, d\tau + K_d \frac{de(t)}{dt}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0379em">δ</span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1.0361em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">K</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">p</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">e</span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1.3443em;vertical-align:-0.3558em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">K</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop"><span class="mop op-symbol small-op" style="margin-right:0.1945em;position:relative;top:-0.0006em">∫</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.9885em"><span style="top:-2.3442em;margin-left:-0.1945em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span><span style="top:-3.2579em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">t</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3558em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">e</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.1132em">τ</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">d</span><span class="mord mathnormal" style="margin-right:0.1132em">τ</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1.355em;vertical-align:-0.345em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">K</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">d</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.01em"><span style="top:-2.655em"><span class="pstrut" style="height:3em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em"><span class="pstrut" style="height:3em"></span><span class="frac-line" style="border-bottom-width:0.04em"></span></span><span style="top:-3.485em"><span class="pstrut" style="height:3em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">e</span><span class="mopen mtight">(</span><span class="mord mathnormal mtight">t</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></p>
<p>And that commanded angle turns into actual torque on the rocket through the gimbal geometry:</p>
<p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>τ</mi><mo>=</mo><msub><mi>F</mi><mi>T</mi></msub><mi>sin</mi><mo>⁡</mo><mo stretchy="false">(</mo><mi>δ</mi><mo stretchy="false">)</mo><mo>⋅</mo><mi>L</mi></mrow><annotation encoding="application/x-tex">\tau = F_T \sin(\delta) \cdot L</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal" style="margin-right:0.1132em">τ</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1389em">F</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">T</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop">sin</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0379em">δ</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.6833em"></span><span class="mord mathnormal">L</span></span></span></span></p>
<p>where <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>F</mi><mi>T</mi></msub></mrow><annotation encoding="application/x-tex">F_T</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1389em">F</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.1389em">T</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span> is the thrust force, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>δ</mi></mrow><annotation encoding="application/x-tex">\delta</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em"></span><span class="mord mathnormal" style="margin-right:0.0379em">δ</span></span></span></span> is the gimbal deflection angle, and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>L</mi></mrow><annotation encoding="application/x-tex">L</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em"></span><span class="mord mathnormal">L</span></span></span></span> is the distance from the gimbal pivot to the rocket's center of mass. Tune <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>K</mi><mi>p</mi></msub></mrow><annotation encoding="application/x-tex">K_p</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">K</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">p</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em"><span></span></span></span></span></span></span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>K</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">K_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">K</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span>, and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>K</mi><mi>d</mi></msub></mrow><annotation encoding="application/x-tex">K_d</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0715em">K</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">d</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span> right, and that torque is what keeps the rocket pointed where it should be throughout the burn, correcting for disturbances in real time.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="airframe-and-avionics">Airframe and avionics<a href="https://watonomous.github.io/humanoid-docs/blog/tvc-rocket-deep-dive#airframe-and-avionics" class="hash-link" aria-label="Direct link to Airframe and avionics" title="Direct link to Airframe and avionics" translate="no">​</a></h2>
<p>The body's a foil-wrapped tube with a 3D-printed nose cone, but the part that actually matters is the gimbal mount at the base: a printed bracket holding two servos at 90° to each other, one for pitch and one for yaw, so the motor can be pushed off-axis in any direction.</p>
<p>Flying the electronics is a custom PCB — Arduino Nano as the flight computer, an MPU6050 for rate/angle data (that's what feeds the PID loop) and a BMP180 barometer. All of it sits in a bay cut into the body tube, wired straight to the servos.</p>
<img src="https://watonomous.github.io/humanoid-docs/img/humanoid/rocketry/pioneer-assembled.jpg" alt="Pioneer fully assembled with avionics bay open" width="400">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="testing-one-milestone-at-a-time">Testing, one milestone at a time<a href="https://watonomous.github.io/humanoid-docs/blog/tvc-rocket-deep-dive#testing-one-milestone-at-a-time" class="hash-link" aria-label="Direct link to Testing, one milestone at a time" title="Direct link to Testing, one milestone at a time" translate="no">​</a></h2>
<p>Since a real launch is a one-shot, motor-consuming event, we can't just wing it and see what happens. Instead there's a staged pipeline, each step cheaper and safer to fail at than the next:</p>
<ol>
<li class=""><strong>MATLAB/Simulink simulation</strong> — check the control loop and gains actually work against a simulated rocket, before touching hardware.</li>
</ol>
<img src="https://watonomous.github.io/humanoid-docs/img/humanoid/rocketry/simulink-model.png" alt="Simulink rocket motor control loop model" width="700">
<img src="https://watonomous.github.io/humanoid-docs/img/humanoid/rocketry/simulink-results.png" alt="Simulink simulation results showing PID response" width="700">
<ol start="2">
<li class=""><strong>BLDC test bench</strong> — get the gimbal actuator and control loop timing working on the bench, driven by a BLDC motor instead of a real rocket motor.</li>
</ol>
<img src="https://watonomous.github.io/humanoid-docs/img/humanoid/rocketry/gimbal-bench-1.jpg" alt="Gimbal and motor mounted on the bench" width="500">
<img src="https://watonomous.github.io/humanoid-docs/img/humanoid/rocketry/gimbal-bench-2.jpg" alt="Rocket clamped in the BLDC test bench" width="500">
<ol start="3">
<li class=""><strong>Motor test bench static fire</strong> — full control loop, real motor, but static-fired on a stand so we can measure thrust and gimbal response without an actual flight.</li>
</ol>
<img src="https://watonomous.github.io/humanoid-docs/img/humanoid/rocketry/static-fire.jpg" alt="Pioneer static fire ignition" width="500">
<ol start="4">
<li class=""><strong>Actual flight test</strong> — Pioneer leaves the pad.</li>
</ol>
<img src="https://watonomous.github.io/humanoid-docs/img/humanoid/rocketry/pioneer-on-pad.jpg" alt="Pioneer on the launch pad before flight" width="500">
<img src="https://watonomous.github.io/humanoid-docs/img/humanoid/rocketry/pioneer-liftoff.jpg" alt="Pioneer liftoff" width="500">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="results">Results<a href="https://watonomous.github.io/humanoid-docs/blog/tvc-rocket-deep-dive#results" class="hash-link" aria-label="Direct link to Results" title="Direct link to Results" translate="no">​</a></h2>
<p>After all the vigorous testing, we got two consecutive successful launches!</p>]]></content>
        <author>
            <name>Wilson</name>
        </author>
        <author>
            <name>Senna</name>
        </author>
        <category label="Rocketry" term="Rocketry"/>
        <category label="TVC" term="TVC"/>
    </entry>
</feed>