<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Tutorial on Mulham Fetna</title>
    <link>https://mulhamfetna.com/tags/tutorial/</link>
    <description>Recent content in Tutorial on Mulham Fetna</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <managingEditor>contact@mulhamfetna.com (Mulham Fetna)</managingEditor>
    <webMaster>contact@mulhamfetna.com (Mulham Fetna)</webMaster>
    <copyright>© 2026 Mulham Fetna</copyright>
    <lastBuildDate>Wed, 16 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://mulhamfetna.com/tags/tutorial/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Calibrating hand tracking to your own hand — with real data from a live session</title>
      <link>https://mulhamfetna.com/projects/ros2-tendon-driven-hand-mujoco-digital-twin-vision-teleoperation/calibration/</link>
      <pubDate>Wed, 16 Sep 2026 00:00:00 +0000</pubDate>
      <author>contact@mulhamfetna.com (Mulham Fetna)</author>
      <guid>https://mulhamfetna.com/projects/ros2-tendon-driven-hand-mujoco-digital-twin-vision-teleoperation/calibration/</guid>
      <description>&lt;div class=&#34;lead text-neutral-500 dark:text-neutral-400 !mb-9 text-xl&#34;&gt;&#xA;  The shipped thresholds were measured on one hand with one webcam. Here is how to measure yours — and&#xA;what a live recording revealed about how far off &amp;ldquo;good enough&amp;rdquo; can be while the twin still looks&#xA;perfect.&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;Symptoms that call for calibration&#xA;    &lt;div id=&#34;symptoms-that-call-for-calibration&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#symptoms-that-call-for-calibration&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;What you see in the published flexions&lt;/th&gt;&#xA;          &lt;th&gt;Cause&lt;/th&gt;&#xA;          &lt;th&gt;Change&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;A fist, but flexion stays below 1.0&lt;/td&gt;&#xA;          &lt;td&gt;your fist angle is &lt;strong&gt;above&lt;/strong&gt; the curled limit&lt;/td&gt;&#xA;          &lt;td&gt;&lt;strong&gt;raise&lt;/strong&gt; &lt;code&gt;*_CURLED_ANGLE&lt;/code&gt; to your fist reading&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Flexion hits 1.0 with the hand half closed&lt;/td&gt;&#xA;          &lt;td&gt;curled limit too high&lt;/td&gt;&#xA;          &lt;td&gt;&lt;strong&gt;lower&lt;/strong&gt; &lt;code&gt;*_CURLED_ANGLE&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Flexion above 0 with a relaxed open hand&lt;/td&gt;&#xA;          &lt;td&gt;your open angle is &lt;strong&gt;below&lt;/strong&gt; the straight limit&lt;/td&gt;&#xA;          &lt;td&gt;&lt;strong&gt;lower&lt;/strong&gt; &lt;code&gt;*_STRAIGHT_ANGLE&lt;/code&gt; to your open reading&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;The thumb flickers&lt;/td&gt;&#xA;          &lt;td&gt;thumb window too narrow for your jitter&lt;/td&gt;&#xA;          &lt;td&gt;widen it (&lt;a href=&#34;https://mulhamfetna.com/projects/ros2-tendon-driven-hand-mujoco-digital-twin-vision-teleoperation/thumb-thresholds/&#34; &gt;Part 8&lt;/a&gt;)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&#xA;  &#xA;  &#xA;  &#xA;  &#xA;&#xA;&#xA;&#xA;&lt;div&#xA;  &#xA;    class=&#34;flex px-4 py-3 rounded-md shadow bg-primary-100 dark:bg-primary-900&#34;&#xA;  &#xA;  &gt;&#xA;  &lt;span&#xA;    &#xA;      class=&#34;text-primary-400 pe-3 flex items-center&#34;&#xA;    &#xA;    &gt;&#xA;    &lt;span class=&#34;relative block icon&#34;&gt;&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 384 512&#34;&gt;&lt;path fill=&#34;currentColor&#34; d=&#34;M112.1 454.3c0 6.297 1.816 12.44 5.284 17.69l17.14 25.69c5.25 7.875 17.17 14.28 26.64 14.28h61.67c9.438 0 21.36-6.401 26.61-14.28l17.08-25.68c2.938-4.438 5.348-12.37 5.348-17.7L272 415.1h-160L112.1 454.3zM191.4 .0132C89.44 .3257 16 82.97 16 175.1c0 44.38 16.44 84.84 43.56 115.8c16.53 18.84 42.34 58.23 52.22 91.45c.0313 .25 .0938 .5166 .125 .7823h160.2c.0313-.2656 .0938-.5166 .125-.7823c9.875-33.22 35.69-72.61 52.22-91.45C351.6 260.8 368 220.4 368 175.1C368 78.61 288.9-.2837 191.4 .0132zM192 96.01c-44.13 0-80 35.89-80 79.1C112 184.8 104.8 192 96 192S80 184.8 80 176c0-61.76 50.25-111.1 112-111.1c8.844 0 16 7.159 16 16S200.8 96.01 192 96.01z&#34;/&gt;&lt;/svg&gt;&#xA;&lt;/span&gt;&#xA;  &lt;/span&gt;&#xA;&#xA;  &lt;span&#xA;    &#xA;      class=&#34;dark:text-neutral-300&#34;&#xA;    &#xA;    &gt;&lt;strong&gt;Calibrate against the numbers, not the render.&lt;/strong&gt; With the current force-control tuning, the&#xA;simulated finger snaps shut past flexion ≈ 0.51 (&lt;a href=&#34;https://mulhamfetna.com/projects/ros2-tendon-driven-hand-mujoco-digital-twin-vision-teleoperation/tendon-physics-switch/&#34; &gt;Part 11&lt;/a&gt;),&#xA;so most calibration errors are invisible in the viewer. Watch &lt;code&gt;ros2 topic echo /hand/target_flexions&lt;/code&gt;.&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;Real data: what a live session produced&#xA;    &lt;div id=&#34;real-data-what-a-live-session-produced&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#real-data-what-a-live-session-produced&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;MuJoCo&amp;rsquo;s viewer has a &lt;strong&gt;Control&lt;/strong&gt; panel showing the live force of every motor. Since the force is&#xA;\(F = 50 - 100 \cdot \text{flexion}\), every recorded frame gives back the exact flexion the tracker&#xA;published: &lt;strong&gt;flexion = (50 − F) / 100&lt;/strong&gt;.&lt;/p&gt;</description>
      <media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://mulhamfetna.com/projects/ros2-tendon-driven-hand-mujoco-digital-twin-vision-teleoperation/calibration/cover.png" />
    </item>
    
    <item>
      <title>Run the tendon-driven hand digital twin in 10 minutes</title>
      <link>https://mulhamfetna.com/projects/ros2-tendon-driven-hand-mujoco-digital-twin-vision-teleoperation/quickstart/</link>
      <pubDate>Wed, 16 Sep 2026 00:00:00 +0000</pubDate>
      <author>contact@mulhamfetna.com (Mulham Fetna)</author>
      <guid>https://mulhamfetna.com/projects/ros2-tendon-driven-hand-mujoco-digital-twin-vision-teleoperation/quickstart/</guid>
      <description>&lt;div class=&#34;lead text-neutral-500 dark:text-neutral-400 !mb-9 text-xl&#34;&gt;&#xA;  Clone, run one setup script, run one Compose command — and a webcam window and a MuJoCo viewer open&#xA;side by side, with a simulated hand that closes when you close yours. Here are four ways in,&#xA;from the full stack down to the bare model.&#xA;&lt;/div&gt;&#xA;&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;low&#34;&#xA;    alt=&#34;What a working setup looks like: MediaPipe tracker window and the MuJoCo twin moving together&#34;&#xA;    src=&#34;https://mulhamfetna.com/projects/ros2-tendon-driven-hand-mujoco-digital-twin-vision-teleoperation/hero_teleoperation.gif&#34;&#xA;    &gt;&lt;figcaption&gt;The goal of this article: both windows open, and the twin follows your hand.&lt;/figcaption&gt;&lt;/figure&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;What you need&#xA;    &lt;div id=&#34;what-you-need&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#what-you-need&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Requirement&lt;/th&gt;&#xA;          &lt;th&gt;Check with&lt;/th&gt;&#xA;          &lt;th&gt;Notes&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Linux desktop, X11 or XWayland&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;echo $DISPLAY&lt;/code&gt; → &lt;code&gt;:0&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Wayland sessions work through XWayland&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Docker Engine + Compose v2&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;docker compose version&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Built with Docker 29.8 / Compose 5.5&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;A webcam&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;ls /dev/video0&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Close any other app using it&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;GPU device nodes&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;ls /dev/dri&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Intel/AMD out of the box; NVIDIA needs the container toolkit (&lt;a href=&#34;https://mulhamfetna.com/projects/ros2-tendon-driven-hand-mujoco-digital-twin-vision-teleoperation/docker-gui-camera-gpu/&#34; &gt;Part 18&lt;/a&gt;)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;~5 GB of disk&lt;/td&gt;&#xA;          &lt;td&gt;&lt;/td&gt;&#xA;          &lt;td&gt;images: vision 2.9 GB, twin 1.7 GB&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;No ROS installation is needed on the host — ROS 2 Jazzy lives inside the containers.&lt;/p&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;Four ways to run it&#xA;    &lt;div id=&#34;four-ways-to-run-it&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#four-ways-to-run-it&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;div&#xA;  class=&#34;tab__container w-full&#34;&#xA;  &#xA;  &gt;&#xA;  &lt;div class=&#34;tab__nav&#34; role=&#34;tablist&#34;&gt;&#xA;    &lt;div class=&#34;flex flex-wrap gap-1&#34;&gt;&lt;button&#xA;          class=&#34;tab__button px-3 py-2 text-sm font-semibold border-b-2 border-transparent rounded-t-md hover:bg-neutral-200 dark:hover:bg-neutral-700 tab--active&#34;&#xA;          role=&#34;tab&#34;&#xA;          aria-selected=&#34;true&#34;&#xA;          data-tab-index=&#34;0&#34;&#xA;          data-tab-label=&#34;Docker Compose (full stack)&#34;&gt;&#xA;          &lt;span class=&#34;flex items-center gap-1&#34;&gt;&#xA;            &#xA;            Docker Compose (full stack)&#xA;          &lt;/span&gt;&#xA;        &lt;/button&gt;&lt;button&#xA;          class=&#34;tab__button px-3 py-2 text-sm font-semibold border-b-2 border-transparent rounded-t-md hover:bg-neutral-200 dark:hover:bg-neutral-700 &#34;&#xA;          role=&#34;tab&#34;&#xA;          aria-selected=&#34;false&#34;&#xA;          data-tab-index=&#34;1&#34;&#xA;          data-tab-label=&#34;Single Python script&#34;&gt;&#xA;          &lt;span class=&#34;flex items-center gap-1&#34;&gt;&#xA;            &#xA;            Single Python script&#xA;          &lt;/span&gt;&#xA;        &lt;/button&gt;&lt;button&#xA;          class=&#34;tab__button px-3 py-2 text-sm font-semibold border-b-2 border-transparent rounded-t-md hover:bg-neutral-200 dark:hover:bg-neutral-700 &#34;&#xA;          role=&#34;tab&#34;&#xA;          aria-selected=&#34;false&#34;&#xA;          data-tab-index=&#34;2&#34;&#xA;          data-tab-label=&#34;Twin only, no camera&#34;&gt;&#xA;          &lt;span class=&#34;flex items-center gap-1&#34;&gt;&#xA;            &#xA;            Twin only, no camera&#xA;          &lt;/span&gt;&#xA;        &lt;/button&gt;&lt;button&#xA;          class=&#34;tab__button px-3 py-2 text-sm font-semibold border-b-2 border-transparent rounded-t-md hover:bg-neutral-200 dark:hover:bg-neutral-700 &#34;&#xA;          role=&#34;tab&#34;&#xA;          aria-selected=&#34;false&#34;&#xA;          data-tab-index=&#34;3&#34;&#xA;          data-tab-label=&#34;Model viewer&#34;&gt;&#xA;          &lt;span class=&#34;flex items-center gap-1&#34;&gt;&#xA;            &#xA;            Model viewer&#xA;          &lt;/span&gt;&#xA;        &lt;/button&gt;&lt;/div&gt;&#xA;  &lt;/div&gt;&#xA;  &lt;div class=&#34;tab__content mt-4&#34;&gt;&lt;div class=&#34;tab__panel tab--active&#34; data-tab-index=&#34;0&#34;&gt;&#xA;        &lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://github.com/mulhamfetna/ros2-tendon-driven-hand-mujoco-digital-twin-vision-teleoperation.git&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ros2-tendon-driven-hand-mujoco-digital-twin-vision-teleoperation&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./setup_host.sh              &lt;span class=&#34;c1&#34;&gt;# X11 access for the containers + camera/GPU checks (once per login)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker compose up --build    &lt;span class=&#34;c1&#34;&gt;# builds both images, starts vision_tracker and mujoco_twin&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;Stop with &lt;code&gt;Ctrl+C&lt;/code&gt;, then &lt;code&gt;docker compose down&lt;/code&gt; to release the camera.&lt;/p&gt;</description>
      <media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://mulhamfetna.com/projects/ros2-tendon-driven-hand-mujoco-digital-twin-vision-teleoperation/quickstart/cover.png" />
    </item>
    
  </channel>
</rss>
