---
// /series6（フィジカルAI研究室）の見出しの下に置く解説（2026-11-07）
// 1 研究室の構成：実機の動画と、手元に置くもの・時間で借りるものの一覧（矢印の図は 2026-11-07 にやめた）
//   動画は R2 の lab-setup-pi05-run-v2.mp4（2026-10-29 の横からの録画 IMG_4222.MOV の12〜140秒を、右寄りに4:3で切り出し6倍速。
//   元の録画は腕を立てた姿勢で上が画面の外に出るので、腕が下りてから箱に入れ終わるまでを使う）
// 2 いま回している実験：お手本 → 学習 → 実機 → 人の直し → 直した成功を学習に足す、のループと各段の数字
// 3 いま調べていること：爪のサーボの電流（2026-11-07 追加。並びは実験のあと・技術の前）
// 4 使っている技術：π0.5・追加学習（LoRA）・借りる GPU・推論サーバー・巻き戻しと人の直し
// 絵は public/site/lab/（run-poster.webp は動画の最初のコマ、
// top-camera.webp は pi05_20261106_183926 の上のカメラの録画（KIOXIA runs/pi05_policy/…/recording/top.mp4、1920×1080）の125秒目。
// マットの左・右・下の縁から傾きを直して右寄りに4:3で切り出し、明るさを少し上げた。元は iCloud の
// フィジカルAI研究室を作る/series6_guide_images/）
// 数字はどれも LOG の記録の値。新しい LOG で数字が変わったら、ここも書き換える
type Link = { log: string; slug: string; t: string };

// 構成は、手元に置くものと時間で借りるものの2つに分ける（2026-11-07 に矢印の図から改めた）
const kit: { group: string; items: { h: string; p: string }[] }[] = [
  { group: '手元に置くもの', items: [
    { h: 'mechArm 270', p: '6つの関節を持つ小型のロボットアーム。中の Raspberry Pi が関節を動かす' },
    { h: '上のカメラ', p: '真上に付けたスマホ。π0.5 が見るのはこの画像だけ' },
    { h: 'ゲームパッド', p: 'AI が失敗しかけたとき、人が関節を直す。3,198円の互換品' },
    { h: 'Mac', p: '画像と関節の角度を記録し、借りた GPU とやり取りする' },
  ] },
  { group: '時間で借りるもの', items: [
    { h: 'Runpod の A40', p: 'π0.5 の学習と推論をする GPU。メモリ 48GB、1時間あたり約98円' },
    { h: 'Hugging Face', p: '学習済みのモデル（6.3GB）の置き場所' },
  ] },
];

const loop: { h: string; num: string; unit: string; p: string; links: Link[] }[] = [
  { h: 'お手本を集める', num: '19', unit: '本',
    p: '要所の姿勢だけ手でアームに教え、間は再生でつないで録りました。ブロックの置き場所は5か所です。',
    links: [
      { log: 'LOG349', slug: 'drag-teach-waypoint-replay', t: '手で教えた動きを再生' },
      { log: 'LOG352', slug: 'teach-replay-19-demos', t: 'お手本19本' },
    ] },
  { h: 'π0.5 に覚えさせる', num: '4,000', unit: 'ステップ',
    p: '借りた A40 で追加学習し、学習の誤差（loss）は 0.0858 から 0.0037 に下がりました。',
    links: [
      { log: 'LOG341', slug: 'pi05-mecharm-lora-2000-steps', t: '最初の学習' },
      { log: 'LOG355', slug: 'pi05-retrain-five-positions', t: '5か所で学習し直す' },
      { log: 'LOG358', slug: 'pi05-learned-the-pauses', t: '待ち時間まで覚えた' },
    ] },
  { h: '実機で動かす', num: '9/15', unit: '回',
    p: '3か所に5回ずつブロックを置き、人が手を出さずに箱へ入れた回数です。腕を伸ばしきる位置は5回中1回でした。',
    links: [
      { log: 'LOG361', slug: 'pi05-first-block-in-box', t: '初めて箱に入れた' },
      { log: 'LOG401', slug: 'pi05-weak-position-d', t: '回数で測る' },
    ] },
  { h: '失敗しかけたら人が直す', num: '13', unit: '秒',
    p: '動きを巻き戻し、ゲームパッドで関節を直して AI に戻すまでの、1回あたりの中央の値です。キーで直していた頃は41〜51秒でした。',
    links: [
      { log: 'LOG403', slug: 'rewind-and-correct-pi05', t: '巻き戻しの仕組み' },
      { log: 'LOG446', slug: 'gamepad-correction-mecharm-270-settled', t: 'ゲームパッドの形' },
      { log: 'LOG450', slug: 'gamepad-fixes-mecharm-270-ai-in-13-seconds', t: '1回13秒に' },
    ] },
  { h: '直した成功を学習に足す', num: '11', unit: '本',
    p: '人が直して成功した記録をお手本に足し、前のモデルから1,500ステップ続けて学び直します。',
    links: [
      { log: 'LOG417', slug: 'retrain-pi05-with-human-corrections', t: '直した5回で学び直す' },
      { log: 'LOG422', slug: 'retrained-pi05-still-needs-human-corrections', t: 'それでも直しが要った' },
    ] },
];

const tech: { name: string; sub: string; p: string; fig?: boolean; links: Link[] }[] = [
  { name: 'π0.5', sub: 'Physical Intelligence', fig: true,
    p: '米国の Physical Intelligence 社が公開している、ロボット用の AI のモデルです。上のカメラの画像、6つの関節と爪の角度、指示文（赤いブロックを白い箱に入れる）を受け取り、次の1秒ぶん（10コマ）の関節の角度を返します。どの順番で動くかを書いたプログラムはありません。',
    links: [{ log: 'LOG337', slug: 'pi05-mecharm-demo-to-inference', t: 'mechArm 270 で動かすまでの流れ' }] },
  { name: '追加学習', sub: 'LoRA',
    p: 'たくさんのロボットのデータで学習済みの π0.5 に、mechArm 270 のお手本だけを足して覚えさせます。モデル全体ではなく、足した小さな部品だけを学習するので、A40 を1枚借りれば足ります。',
    links: [{ log: 'LOG341', slug: 'pi05-mecharm-lora-2000-steps', t: '予測がお手本とほぼ一致' }] },
  { name: '時間で借りる GPU', sub: 'Runpod',
    p: 'π0.5 は NVIDIA の GPU を積んだ Linux のマシンでしか動かず、Mac では動きません。そこで GPU を時間単位で借ります。学習は自動で回し、終わるとモデルを持ち帰って、借りたマシンを消します。',
    links: [{ log: 'LOG401', slug: 'pi05-weak-position-d', t: 'モデルを Hugging Face に置いた' }] },
  { name: '推論サーバー', sub: 'Remote inference',
    p: '借りたマシンの上で π0.5 を起動し、Mac とは SSH の中継でつなぎます。π0.5 の計算は1回平均97ミリ秒、Mac から送って答えが返るまでの往復は391ミリ秒でした（A40）。',
    links: [{ log: 'LOG326', slug: 'openpi-remote-inference-first-run', t: '借りた GPU で初めて動かした' }] },
  { name: '巻き戻しと人の直し', sub: 'Human correction',
    p: '米国の MicroFactory の卓上ロボットを参考にしました。失敗しかけた区間をアームごと巻き戻し、人が関節を直してから AI に戻します。直す人の手はカメラに写らないので、直した動きをそのまま学習データにできます。',
    links: [{ log: 'LOG403', slug: 'rewind-and-correct-pi05', t: '直した動きだけを学習データにする' }] },
];

// 4 いま調べていること：爪のサーボの電流の値（2026-11-07 の実機。0.5秒ごとの中央値。元は KIOXIA の diag/servo_current_20261107/180051_pad）
// 帯の時刻は値から読んだ（空で閉じた：51〜65秒、つかんだ：79〜109秒）。
// 大きい数字（15前後・870前後）は LOG461 の書き方にそろえる（2026-11-08。最初は0.5秒ごとの値から16と960と書いていた）
import grip from '../data/lab/gripper_current_20261107.json';
const CW = 800, CH = 300, PL = 64, PR = 12, PT = 36, PB = 34, TMAX = 145, YMIN = -100, YMAX = 1050;
const cx = (t: number) => PL + (t / TMAX) * (CW - PL - PR);
const cy = (v: number) => PT + (1 - (v - YMIN) / (YMAX - YMIN)) * (CH - PT - PB);
const gripPath = (grip.points as [number, number][]).map(([t, v], i) => `${i ? 'L' : 'M'}${cx(t).toFixed(1)},${cy(v).toFixed(1)}`).join('');
const bands = [
  { t0: 51, t1: 65, label: '空で閉じた' },
  { t0: 79, t1: 109, label: 'つかんだ' },
];
const yTicks = [0, 500, 1000];
const xTicks = [0, 30, 60, 90, 120];
---
<section class="sec lg"><div class="panel">
  <h2 class="sec-h">研究室の構成 | Setup</h2>
  <p class="lg-lead">机の上のアームとカメラと Mac に、時間で借りる GPU を足しただけの構成です。Mac が上のカメラの画像と関節の角度を借りた GPU へ送り、π0.5 が次の1秒ぶんの関節の角度を返して、Mac がそれをアームへ渡します。</p>
  <div class="lg-setup">
    <figure class="lg-run">
      <video src="/media/lab-setup-pi05-run-v2.mp4" poster="/site/lab/run-poster.webp" width="1200" height="900" autoplay muted loop playsinline preload="metadata"
        aria-label="mechArm 270 が赤いブロックをつかみ、持ち上げて右の白い箱に入れるまで"></video>
      <figcaption>π0.5 が動かした mechArm 270。人の手を入れずに成功した1回（2026年10月29日・6倍速）</figcaption>
    </figure>
    <div class="lg-kit">
      {kit.map((g) => (
        <div class="lg-kit-group">
          <h3 class="lg-kit-h">{g.group}</h3>
          <dl class="lg-items">
            {g.items.map((it) => (<div><dt>{it.h}</dt><dd>{it.p}</dd></div>))}
          </dl>
        </div>
      ))}
    </div>
  </div>
</div></section>

<section class="sec lg"><div class="panel">
  <h2 class="sec-h">いま回している実験 | Experiment</h2>
  <p class="lg-lead">赤いブロックをつかんで、白い箱に入れる。この1つの作業を π0.5 に覚えさせ、失敗しかけた所を人が直し、直した動きをまた学習に回しています。人の直しが要らなくなるまで、このループを回します。</p>
  <ol class="lg-loop">
    {loop.map((s, i) => (
      <li class="lg-step">
        <span class="lg-step-no">{String(i + 1).padStart(2, '0')}</span>
        <h3 class="lg-step-h">{s.h}</h3>
        <p class="lg-num">{s.num}<small>{s.unit}</small></p>
        <p class="lg-p">{s.p}</p>
        <ul class="lg-links">
          {s.links.map((l) => <li><a href={`/record/${l.slug}`} title={l.t} aria-label={`${l.log} ${l.t}`}><b>{l.log}</b><i class="ms">arrow_forward</i></a></li>)}
        </ul>
      </li>
    ))}
  </ol>
  <p class="lg-return"><i class="ms" aria-hidden="true">replay</i>05 のあとは 03 に戻り、学び直したモデルで実機をもう一度動かします</p>
  <p class="lg-note">数字は 2026年11月6日（LOG450）までの記録の値です。</p>
</div></section>

<section class="sec lg"><div class="panel">
  <h2 class="sec-h">いま調べていること | Now</h2>
  <p class="lg-lead">お手本の記録に、爪のモーターの電流を足せるかを調べています。11月7日、実機で爪を空で閉じる・ブロックをつかむ・放すを行い、その間の値を1秒に約10回読みました。</p>
  <div class="lg-now">
    <div class="lg-now-nums">
      <div><p class="lg-now-label">空で閉じた</p><p class="lg-num">15<small>前後</small></p></div>
      <div><p class="lg-now-label">ブロックをつかんだ</p><p class="lg-num">870<small>前後</small></p></div>
      <p class="lg-p">値は50倍以上違います。つかめたか空振りしたかが、カメラを見なくても分かります。</p>
      <ul class="lg-links"><li><a href="/record/reading-mecharm-270-servo-current-for-learning" title="電流を読んだ記録" aria-label="LOG461 電流を読んだ記録"><b>LOG461</b>電流を読んだ記録<i class="ms">arrow_forward</i></a></li></ul>
    </div>
    <figure class="lg-chart">
      <svg viewBox={`0 0 ${CW} ${CH}`} role="img" aria-label="爪のサーボの電流の値の時間の変化。空で閉じた間は15前後、ブロックをつかんだ直後に最も高くなり、30秒ほどで800前後までゆっくり下がり、放すとマイナス50前後になる">
        {bands.map((b) => (
          <g>
            <rect x={cx(b.t0)} y={PT} width={cx(b.t1) - cx(b.t0)} height={CH - PT - PB} fill="#f2f2f2" />
            <text x={(cx(b.t0) + cx(b.t1)) / 2} y={PT - 12} text-anchor="middle" class="lg-chart-band">{b.label}</text>
          </g>
        ))}
        {yTicks.map((v) => (<text x={PL - 10} y={cy(v) + 4} text-anchor="end" class="lg-chart-tick">{v}</text>))}
        <line x1={PL} x2={CW - PR} y1={cy(0)} y2={cy(0)} stroke="#d6d6d6" stroke-width="1" />
        {xTicks.map((t) => (<text x={cx(t)} y={CH - 10} text-anchor="middle" class="lg-chart-tick">{t}</text>))}
        <text x={CW - PR} y={CH - 10} text-anchor="end" class="lg-chart-tick">秒</text>
        <path d={gripPath} fill="none" stroke="#242424" stroke-width="2.5" stroke-linejoin="round" />
      </svg>
      <figcaption>爪のサーボの電流の値（単位なしの読み値・0.5秒ごとの中央値）。つかんだ直後に最も高くなり、30秒ほどかけて800前後までゆっくり下がりました。つかんだブロックを引っ張ったときの変化は、この下がり方に埋もれて見えていません。</figcaption>
    </figure>
  </div>
</div></section>

<section class="sec lg"><div class="panel">
  <h2 class="sec-h">使っている技術 | Technology</h2>
  <dl class="lg-tech">
    {tech.map((t) => (
      <div class="lg-tech-row">
        <dt><span class="lg-tech-name">{t.name}</span><span class="lg-tech-sub">{t.sub}</span></dt>
        <dd>
          <div class={t.fig ? 'lg-tech-body has-fig' : 'lg-tech-body'}>
            <div>
              <p class="lg-p">{t.p}</p>
              <ul class="lg-links">
                {t.links.map((l) => <li><a href={`/record/${l.slug}`}><b>{l.log}</b>{l.t}<i class="ms">arrow_forward</i></a></li>)}
              </ul>
            </div>
            {t.fig && (
              <figure class="lg-fig">
                <img src="/site/lab/top-camera.webp" alt="真上のカメラの画像。mechArm 270 の爪が赤いブロックをつかみ、右に白い箱がある" width="800" height="600" loading="lazy" />
                <figcaption>上のカメラの画像。傾きを直して切り出しています。π0.5 には、この画像を 384×216 に縮めて渡します</figcaption>
              </figure>
            )}
          </div>
        </dd>
      </div>
    ))}
  </dl>
</div></section>

<style>
  .lg { padding-bottom: 0; }
  .lg-lead { margin: -16px 0 32px; max-width: 46em; font: 400 16px/28px var(--sans); color: var(--ink-2); }
  .lg-p { margin: 0; font: 400 15px/27px var(--sans); color: var(--ink-2); word-break: auto-phrase; text-wrap: pretty; }

  /* 1 構成：3つの場所と、その間を行き来するもの */
  /* 写真はブロックから箱まで入れたいので、切り抜かずに元の比率のまま置く */
  .lg-setup { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 32px; align-items: start; }
  .lg-run { margin: 0; }
  .lg-run video { display: block; width: 100%; height: auto; aspect-ratio: 4 / 3; border-radius: 8px; background: #e9e7e2; }
  .lg-run figcaption { margin: 8px 0 0; font: 400 12px/18px var(--sans); color: var(--ink-3); }
  /* 手元に置くもの・時間で借りるもの を、それぞれ面で囲んで分ける */
  .lg-kit { display: grid; gap: 12px; }
  .lg-kit-group { padding: 24px; border-radius: 8px; background: var(--bg); }
  .lg-kit-h { margin: 0 0 16px; font: 700 18px/28px var(--sans); color: var(--ink); }
  .lg-items { margin: 0; display: grid; gap: 14px; }
  .lg-items dt { font: 700 15px/24px var(--sans); color: var(--ink); }
  .lg-items dd { margin: 2px 0 0; font: 400 14px/22px var(--sans); color: var(--ink-2); word-break: auto-phrase; }

  /* 2 実験のループ */
  .lg-loop { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 12px; }
  /* 5枚の見出し・数字・文・リンクの高さを、subgrid で行ごとにそろえる（段々にしない） */
  .lg-step { display: grid; grid-row: span 5; grid-template-rows: subgrid; row-gap: 0; align-content: start; padding: 20px; border-radius: 8px; background: var(--bg); }
  .lg-step-no { font: 700 13px/20px var(--sans); color: var(--ink-3); font-variant-numeric: tabular-nums; }
  .lg-step-h { align-self: start; margin: 4px 0 12px; font: 700 16px/24px var(--sans); color: var(--ink); word-break: auto-phrase; }
  .lg-num { align-self: start; white-space: nowrap; margin: 0 0 12px; font: 700 clamp(32px, 2.8vw, 40px)/1 var(--sans); color: var(--ink); font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
  .lg-num small { margin-left: 4px; font: 600 14px/1 var(--sans); color: var(--ink-2); letter-spacing: 0; }
  .lg-step .lg-p { font-size: 14px; line-height: 24px; }
  .lg-step .lg-links { margin: 0; padding-top: 16px; gap: 6px; align-self: start; }
  .lg-step .lg-links a { gap: 4px; padding: 5px 8px 5px 10px; }
  .lg-step .lg-links a { background: #fff; }
  .lg-step .lg-links a:hover { background: #e6e6e6; }
  .lg-return { display: flex; align-items: center; gap: 10px; margin: 12px 0 0; padding: 14px 20px; border-radius: 8px; background: var(--dark); color: #fff; font: 600 15px/24px var(--sans); }
  .lg-return .ms { font-size: 22px; }
  .lg-note { margin: 16px 0 0; font: 400 13px/22px var(--sans); color: var(--ink-3); }

  /* 4 いま調べていること */
  .lg-now { display: grid; grid-template-columns: 240px minmax(0, 1fr); gap: 40px; align-items: start; }
  .lg-now-nums { display: grid; gap: 20px; }
  .lg-now-label { margin: 0 0 6px; font: 600 14px/20px var(--sans); color: var(--ink-2); }
  .lg-now-nums .lg-num { margin: 0; }
  .lg-now-nums .lg-links { margin: 0; grid-column: 1 / -1; }
  .lg-chart { margin: 0; }
  .lg-chart svg { display: block; width: 100%; height: auto; }
  .lg-chart-tick { font: 400 12px var(--sans); fill: var(--ink-3); }
  .lg-chart-band { font: 600 14px var(--sans); fill: var(--ink); }
  .lg-chart figcaption { margin: 12px 0 0; max-width: 46em; font: 400 13px/22px var(--sans); color: var(--ink-3); }

  /* 3 技術 */
  .lg-tech { margin: 0; display: grid; }
  .lg-tech-row { display: grid; grid-template-columns: 240px minmax(0, 1fr); gap: 32px; padding: 28px 0; border-top: 1px solid #e6e6e6; }
  .lg-tech-row:last-child { padding-bottom: 0; }
  .lg-tech-row dt { display: grid; align-content: start; gap: 2px; }
  .lg-tech-name { font: 700 20px/30px var(--sans); color: var(--ink); }
  .lg-tech-sub { font: 400 13px/20px var(--sans); color: var(--ink-3); }
  .lg-tech-row dd { margin: 0; }
  .lg-tech-body { max-width: 52em; }
  .lg-tech-body.has-fig { max-width: none; display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 32px; align-items: start; }
  .lg-fig { margin: 0; }
  .lg-fig img { display: block; width: 100%; height: auto; border-radius: 6px; }
  .lg-fig figcaption { margin: 8px 0 0; font: 400 12px/18px var(--sans); color: var(--ink-3); }

  /* 記録へのリンク（/series7 の解説と同じ形） */
  .lg-links { list-style: none; margin: 14px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
  .lg-links a { display: inline-flex; align-items: center; gap: 8px; padding: 7px 10px 7px 12px; border-radius: 4px; background: #f2f2f2;
    color: var(--ink); font: 500 13px/20px var(--sans); text-decoration: none; transition: background .15s; }
  .lg-links a b { font-weight: 700; font-variant-numeric: tabular-nums; }
  .lg-links a .ms { font-size: 15px; color: var(--ink-3); transition: transform .2s; }
  .lg-links a:hover { background: #e6e6e6; }
  .lg-links a:hover .ms { transform: translateX(2px); }

  @media (max-width: 1199px) {
    .lg-loop { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  }
  @media (max-width: 1023px) {
    .lg-setup { grid-template-columns: minmax(0, 1fr); gap: 28px; }
    .lg-loop { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .lg-tech-row { grid-template-columns: minmax(0, 1fr); gap: 8px; }
    .lg-now { grid-template-columns: minmax(0, 1fr); gap: 24px; }
    .lg-now-nums { grid-template-columns: 1fr 1fr; }
    .lg-now-nums .lg-p { grid-column: 1 / -1; }
  }
  @media (max-width: 599px) {
    /* 図は幅に合わせて縮むので、文字だけ大きくしておく */
    .lg-chart-tick { font-size: 24px; }
    .lg-chart-band { font-size: 28px; }
    .lg-tech-body.has-fig { grid-template-columns: minmax(0, 1fr); gap: 20px; }
    .lg-fig { max-width: 480px; }
  }
  @media (max-width: 599px) {
    .lg-lead { margin: -16px 0 24px; font-size: 15px; line-height: 26px; }
    .lg-loop { grid-template-columns: minmax(0, 1fr); }
    .lg-num { font-size: 36px; }
    .lg-tech-row { padding: 22px 0; }
    .lg-tech-name { font-size: 18px; line-height: 28px; }
  }
</style>
