pixelstomotors.com を AI で読む入口 ― Gemini のアプリは HTML しか読まない
この記事の素材(コード・ログ・データ 3ファイル・まとめてダウンロードあり)arrow_downwardAIで読む ChatGPT・Claude などで、この記事に質問できます expand_more
Gemini のアプリ(gemini.google.com)は、URL を渡しても .txt や .md のテキストのファイルは読まず、ふつうの Web ページ(HTML)だけを読む。 pixelstomotors.com の TOP に、記録を AI に読ませて聞く入口を作り、ChatGPT・Claude・Gemini で実際に押して確かめて分かったことです。
この入口で変わったことは3つです。
- 何度も来てくれる人が、長いログを読まずに記録を楽しめるようになった。 TOP の帯を開いて質問を1つ選び、ふだん使っている AI のボタンを押すだけで、AI がサイトの記録を読んで答えます。質問は、前に来たときから何が進んだか・失敗した回・自分で始めるなら最初の1本・ハコブくんの説明、の4つです。ページを移らずに TOP の中で開きます。
- Gemini で押した人にも、答えが返るようになった。 記事ページの AIで読む の Gemini は、置いた11月1日から、押した人に読めませんでしたと返していたはずです。サイトの記録には、この日の未明に Gemini 経由で記事の全文ファイル(.md)を読みに来た跡が2件残っています。今は Gemini にだけ HTML のページを読ませています。
- 時間: 相談を始めてから TOP に帯を出すまでが約17分(9時3分に相談、9時20分に公開)。Gemini を含む4つの AI で答えが返るまでが約50分(9時51分)でした。前に同じことをした記録はないので、何分浮いたかは比べられません。
pixelstomotors.com は、ロボットとフィジカルAI(現実の物を動かす AI)の研究を、ひとりで記録して公開しているサイトです。記録はコードと実行ログを全部載せたログなので、人が頭から読む読み物にはなっていません。前に測ったときは、人の何十倍も AI に読まれていました(LOG430)。それでも、何度も来てくれる人が少しはいます。その人たちに、このサイトの楽しみ方を伝えたい、というのが始まりです。
楽しみ方の中身は、AI に読ませて聞くことにしました。ところが4つの AI で試すと、Gemini だけが、サイトの案内(/llms.txt)にアクセスできませんでしたと答えました。サイトの記録を見ると、Gemini は読みに来ていて、サイトは正常に返していました。届いているのに読めない、という状態です。
| やったこと | なぜ | 結果 |
|---|---|---|
TOP に、閉じると1行の帯を置いた | 取説を読むために、ほかのページへ移らせたくなかった | 開くと、質問4つと AI のボタンが出る |
| 4つの AI で質問を押した | 質問が答えとして成り立つかを見たかった | Claude と ChatGPT は成り立った。Gemini のアプリは読めなかった |
サイトの記録と Gemini の API で切り分けた | Gemini だけ読めない理由を知りたかった | アプリはテキストのファイルを読まず、HTML だけ読む |
案内の HTML 版(/llms)を作った | Gemini にも同じ一覧を読ませたかった | Gemini のアプリでも、本文まで読んだ答えが返った |
記事の AIで読む の Gemini を、記事ページに向けた | 全文ファイル(.md)を Gemini が読めないため | Gemini の API で、記事ページを読めることを確かめた |
作業ログ ― TOP に「このサイトの楽しみ方」の帯を置いた
この記事のコード・ログ・データは、1ファイルずつ下に置いています。全文はリンク先にあります。
ファイルの一覧(3本)
01_TopAiGuide.astro.txt ― TopAiGuide.astro(TOP の帯の部品・最後の版)・11,079字
02_ChatGPT.txt ― ChatGPT:失敗した回だけ集めて・4,060字
03_sec04.txt ― 変更の差分(worker・記事ページ・TOP・README)・6,181字
最初は、TOP には入口だけを置き、取説の本体は別のページにする案を出しました。今の TOP には動画・1年・導入前ガイド・4コマ・いまの考え・シリーズ・記録・事業所の8つのセクションが並んでいて、長い取説をそのまま入れるとほかの入口が下に沈むからです。
エイイチの答えは、次のとおりでした。
うちのサイトはそもそも、人がそのまま読むのはかなりきつい(ログなので文章量が多くて読み物として作られていない)でもサイトに何度も来訪している人は少ないけどいるようなので、その人たちにうちのサイトの活用法と楽しみ方(こっちが主かも)を伝えたい。あとそれを読むことによって他のページに遷移してしまうことは避けたい。
これで形が決まりました。別のページには分けず、TOP の中で開く帯にします。
帯はヒーローのすぐ下に置き、閉じると1行にした
帯は、最初の画面(ヒーロー)のすぐ下、解説動画の前に置きました。閉じているときは、このサイトの楽しみ方と一文だけが見える白い帯です。記事ページの AIで読む と同じ開き方(押すとその場で開く)にそろえました。
- ねらい:何度も来ている人が、ページを移らずに、AI に聞く楽しみ方へ入れるようにする
- 変わったこと:TOP の最初の画面の下に、閉じると1行の帯が出る。開くと、①聞きたいことを選ぶ ②ふだん使っている AI で開く、の2段になる
- 見込める効果:TOP の下のセクションを押し下げずに、AI に読ませる使い方を伝えられる。押した数は、サイトの計測(/api/ev-stats)の TOPの楽しみ方 で数える。効果はまだ見込みで、押された数はこれから見る



閉じた帯は目立たなかったので、14秒に1回だけ細い黒い帯を通した
公開して TOP を見たエイイチから、次の指示がありました。
これだと全然目立たないので(と言ってめっちゃ目立たせたわけではない)、ごくたまにふぁーっと黒に左右にスライドして一瞬色が切り替わるみたいなことはできますか?
閉じた帯の上に白い膜を重ね、重ね方を difference(下の色との差を出す重ね方)にしました。白い地は黒に、黒い字は白に反転します。この膜を、左から右へ広げてから右へ抜くように動かします。ページを開いて2.5秒後に1回、そのあとは14秒に1回、入ってから抜けるまで約1.4秒です。帯を開いているあいだと、端末で動きを減らす設定にしている人には出しません。

帯全体が黒に変わる形は、見たエイイチから、もっとさりげない感じがいい、と言われました。膜を帯の幅の2割ほどの細い帯にし、両端をぼかして、約1.1秒ですっと通り抜ける形に変えました。重なった所だけが反転し、帯全体が黒くなることはありません。出る間隔(開いて2.5秒後に1回、そのあと14秒に1回)は同じです。

質問は4つにし、前に来た日を見た人のブラウザに覚えた
質問は、何度も来ている人向けに4つ用意しました。
| 質問 | AI に頼むこと |
|---|---|
前に来たときから、何が進んだ? | 前に来た日より後の記録を、シリーズごとにまとめる。面白い1本は全文を読んで理由も添える |
| 失敗した回だけ集めて | うまくいかなかった回を探し、どこでつまずき、どう直したかを3つ |
自分で始めるなら、最初の1本は? | 最初に読む記録を3本、順番と理由、要る機材と費用(円) |
| ハコブくんに説明してもらう | 4コマのハコブくんの口調で、最近の研究をユーモアを入れて |
最後の1つは遊びです。1つ入っていると、ただの取説ではなく楽しみ方として伝わると考えました。
前に来たときからの質問は、見た人のブラウザに、前に TOP を開いた日を覚えておきます(localStorage の p2m-site-top-visit)。覚えていれば、カードの小さい字が前に来た10月28日より後の記録をまとめる、のように、その人の日付に変わります。覚えていなければ、この2週間の記録になります。
llms.txt に、記録ごとの公開日を足した
AI に読ませるのは、サイトの案内の /llms.txt です。llms.txt は、AI がサイトを読むときの案内を、サイトの一番上に置いておく決まった形のテキストファイルです(llmstxt.org)。このサイトでは、シリーズ・導入前ガイド・記録の一覧と、記録ごとの全文ファイルの住所を書いています。
前に来た日より後の記録を AI に拾わせるには、一覧に日付が要ります。そこで、記録の行に公開日(日本時間)を足しました。
- [LOG436 フィジカルAI研究室を作る Log#20 | ゲームパッドで動いた mechArm 270、遅さは pymycobot の版](https://pixelstomotors.com/record/gamepad-moves-mecharm-270-pymycobot-version): フィジカルAI研究室・2026-11-03 公開(全文の Markdown: https://pixelstomotors.com/record/gamepad-moves-mecharm-270-pymycobot-version.md)
帯の中で押したものは、サイトの計測に残る
帯の中で押したものは、記事ページの AIで読む と同じ仕組み(サイトに組み込んだ自前の計測。LOG430)で記録しています。部品の data-ev に付けた名前で、何を押したかが /api/ev-stats の押したリンク・ボタンの表に出ます。記録するのは押したものの名前と、ページのどの部分か(ai)だけで、入力した内容やコピーした文は残しません。
| 押したもの | 記録に出る名前 |
|---|---|
| 帯を開いた | btn:TOPの楽しみ方:開く |
| 質問を選んだ | btn:TOPの楽しみ方:質問 前に来たときから、何が進んだ? など |
| AI のボタン | TOPの楽しみ方:since chatgpt.com のように、質問と行き先の AI が組で出る |
| 質問文をコピー | btn:TOPの楽しみ方:since:コピー など |
押したあとで、その AI が実際に案内(/llms.txt・/llms)を読みに来たかは、別の記録(/api/cr-stats の AIで読む経由)で見ます。押した数と、AI が実際に読みに来た数の両方を並べて見られます。
気をつけることが2つあります。帯を閉じたときも、開いたときと同じ名前で数えるので、開いた数は少し多めに出ます。1回のページ表示で記録する押したものは8つまでです。エイイチ自身の閲覧は数えない設定(?p2m-notrack=1)にしているので、この表に出るのはほかの人が押した分だけです。
記録が取れているかを、公開した日の10時15分ごろに確かめました。鍵(集計の鍵)は KIOXIA のファイルから読むだけで、表に出していません。
$ K=$(tr -d '\n\r ' < $HOME/mnt/KIOXIA/p2m_stats_key.txt); curl -s -m 90 -H "Authorization: Bearer $K" "https://pixelstomotors.com/api/ev-stats?since=2026-11-03&format=json" -o $HOME/ev.json; python3 -c "
import json;d=json.load(open('$HOME/ev.json'));print(list(d.keys()))
s=json.dumps(d,ensure_ascii=False)
import re
for k,v in d.items():
if isinstance(v,list):
for r in v:
if 'TOPの楽しみ方' in json.dumps(r,ensure_ascii=False): print(k, json.dumps(r,ensure_ascii=False)[:200])
"
['total', 'counted', 'truncated', 'since', 'week', 'who', 'byWeek', 'byPage', 'moves', 'referrers', 'utmSources', 'clicks', 'areas', 'deadClicks']
$ python3 -c "
import json;d=json.load(open('$HOME/ev.json'))
print('total',d['total'],'counted',d['counted'])
print(json.dumps(d['clicks'][:8],ensure_ascii=False)[:900])
print(json.dumps([a for a in d['areas'] if 'ai' in json.dumps(a)],ensure_ascii=False)[:400])
p=[r for r in d['byPage'] if r.get('path') in ('/','/index') or r.get('page')=='/']
print(json.dumps(p,ensure_ascii=False)[:300])
"
total 106 counted 106
[]
[]
[{"path": "/", "views": 12, "medianSeconds": 18, "read25Pct": 42, "read50Pct": 42, "read75Pct": 42, "read100Pct": 42, "deadClicks": 0, "rageClicks": 0, "copies": 0, "videoPlays": 0, "outClicks": 0}]
$ K=$(tr -d '\n\r ' < $HOME/mnt/KIOXIA/p2m_stats_key.txt); curl -s -m 150 -H "Authorization: Bearer $K" "https://pixelstomotors.com/api/ev-stats?since=2026-10-30&format=json" -o $HOME/ev2.json; python3 -c "
import json;d=json.load(open('$HOME/ev2.json'))
print('who',d.get('who'),'total',d['total'],'week',d.get('week'))
print(json.dumps(d['byWeek'],ensure_ascii=False)[:500])
print(json.dumps(d['clicks'][:10],ensure_ascii=False)[:1200])
print([c for c in d['clicks'] if 'AI' in c['target'] or '楽しみ' in c['target']])
"
who None total 1213 week None
[{"week": "2026-11-02", "label": "2026-11-02 〜 11-08", "views": 392, "medianSeconds": 6, "read75Pct": 84, "spPct": 5, "backViews": 0, "outClicks": 0, "deadClicks": 4, "rageClicks": 0, "messageViews": 2, "formStarts": 0, "formSubmits": 0, "formSubmitsValid": 0, "messagesReceived": 0, "humanViews": 35, "botViews": 346, "unknownViews": 11, "unmarkedViews": 0}, {"week": "2026-10-26", "label": "2026-10-26 〜 11-01", "views": 821, "medianSeconds": 6, "read75Pct": 89, "spPct": 6, "backViews": 1, "outCli
[{"target": "/|ヘッダー", "count": 4}, {"target": "btn:次のコマ|ページの中身", "count": 3}, {"target": "btn:メニュー|ヘッダー", "count": 2}, {"target": "iframe:/embeds/LOG408_tate_4koma.html|本文", "count": 1}, {"target": "/manga/ep133|その他", "count": 1}, {"target": "/manga/ep132|前後の記事", "count": 1}, {"target": "/record/lighting-breaks-picking|ページの中身", "count": 1}, {"target": "/record/gemini-api-4koma|ページの中身", "count": 1}, {"target": "/record/check-serving-robot-sim-with-phone|その他", "count": 1}, {"target": "iframe:/embeds/LOG414_sheet_to_assumptions.html|本文", "count": 1}]
[{'target': 'btn:AIで読む:開く|ai', 'count': 1}]
10月30日からの記録に、記事ページの AIで読む を開いた1回(btn:AIで読む:開く)が残っていて、仕組みが動いていることは確かめられました。TOP の帯の分は、公開した日の10時台にはまだ0件でした。エイイチがこの日に何度も押したのは、数えない設定のブラウザからだったためです。
TopAiGuide.astro(TOP の帯の部品・最後の版)
帯の部品の全文です。このあと Gemini の件と黒い帯の動きで直したので、直したあとの最後の版を載せます。
---
// TOP の「このサイトの楽しみ方」(2026-11-03)
// 記録は長いログで、人がそのまま読むのはきつい。何度も来ている人に、AI に読ませて聞く楽しみ方を伝える帯。
// 決めたこと(エイイチ 2026-11-03):活用=AI に読ませて使う方法。楽しみ方を主にする。取説を読むためにほかのページへ移らせない(TOP の中で開く)。
// 形:ヒーローの下に、閉じると1行の帯。開くと、①質問を選ぶ ②ふだん使っている AI で開く。AI にはサイトの案内(/llms.txt)を読ませる。
// AI の開き方・前回の AI の覚え方(p2m-site-ai)は記事ページの「AIで読む」(src/pages/record/[slug].astro)と同じ。
// 「前に来たときから」は、TOP を前に開いた日を見た人のブラウザに覚えておき(p2m-site-top-visit)、その日より後の記録を AI に拾わせる。覚えていなければ「この2週間」。
// 押した数は /api/ev-stats(場所 ai。「TOPの楽しみ方:…」)、AI が案内を読みに来た数は /api/cr-stats の「AIで読む経由」(/llms.txt?via=…)作業ログ ― 4つの AI で質問を押して、答えを確かめた
公開したあと、エイイチが Claude・ChatGPT・Gemini で質問を押し、返ってきた答えを貼ってくれました。答えは全文を残します。
Claude:ハコブくんに説明してもらう
LOG436・LOG434・LOG430 の中身を拾い、ハコブくんの口調で話しています。最後の出典の注記に、一覧は長いため前半のみ読みました、とありました。
ハコブくんとして話すために、まずサイトの案内から最近の記録を確認します。
こんにちは、ハコブだよ!ふだんは病院で薬を運んでるけど、今日はエイイチの「最近なにしてるの?」を運んできたよ。ここ数日の記録を読んだら、エイイチはだいたい3つの現場を行ったり来たりしてた。
**① 机の上のアームに、ゲームパッドで手を貸す**
フィジカルAI研究室では、小さなロボットアーム mechArm 270 に、AI(π0.5)を使ってブロックを箱に入れる動きを覚えさせてる。でも、人が直した動きで学び直しても、まだ途中で人の手直しが要るんだって。だから今は「AIが迷ったら人がゲームパッドで直し、その直しも記録して学習に使う」仕組みを作ってるところ。
11月3日の朝、初めて実物のアームをゲームパッドで動かしたら、1回押すたびに約1.6秒待たされた。原因を追ったら、アームの中の Raspberry Pi で動く受け口のプログラムが、想定と違う版のライブラリ(pymycobot 4.0.4)を読んでいた。指令を送るたびにアームの返事を0.5秒ずつ3回待って、同じ指令を3回書いてたんだ。返事をしない相手に「聞こえてる?」を3回ずつ。律儀すぎるよね。ボクも呼ばれたらすぐ返事しようっと。
起動スクリプトを1行直したら、送信は約0.02秒になって、長押しで毎秒約8°動くようになった。気づいてから直るまで約6分、費用は0円。ただ、動きはまだなめらかとは言えない。次は、押している間だけ一定の速さで動き続ける jog という命令で、このアームがどこまでなめらかに動けるか、限界を測るんだって。
**② 配膳ロボットの「にらみ合い」は店員さんが解く**
もう一つはサービスロボット導入シミュレーション。お店に配膳ロボットを入れる前に、待ち時間や必要な人数、ロボットが止まる場所を試算するシリーズだよ。Unity で再現したファミレスで、ロボット2台が狭い通路で向かい合ったら、9分間にらみ合ってた。どっちも相手がどくのを待ってたんだ。わかるなあ。ボクも昔、廊下で看護師さんとお見合いしないように設定してもらったから。
実物の動画4本を見直すと、本物のお店でもロボットどうしでは解けず、店員さんが来るまで18〜53秒以上、手で直す作業は5秒前後だった。どっちが譲るかの決まりは、どのメーカーも公開してない。そこで「30秒動けなかったら店員さんが助けに来る」作りに変えて、店員さんがどれだけ手を取られるかを数字で出せるようにした。試算のページでは、店ごとの Unity の動画も見られるようになったよ。
**③ サイトは人より AI に読まれてる**
研究の外側では、サイトの読まれ方を測ってた。1週間で、AIや検索エンジンのクローラーの訪問が約1万1千回、人のページ表示は163回。ざっと70倍! ChatGPT が利用者のために記事を読んだのは60回で、そこから実際に来た人は1人だった。AIに読まれることと、人に来てもらうことは別の話だって、数字ではっきりしたんだ。
ちなみに、このお話を作るためにいまAIがサイトを読んだから、カウンターがまた1つ増えてるかも。読んでくれたのが人なら、うれしいな。
ほかにも、考察記事を YouTube の掛け合い動画にしたり、AIとの作業の「イラッ」を14本のショートにしたり、ボクの4コマの英語版を描き直さずに作ったりしてた。ボク、海外デビューも近いかも。
**まとめると**
3つに共通してるのは、ロボットやAIだけでは最後の一歩が届かないところで、人がどう手を貸すかを、ちゃんと測って数字にしてること。アームには人のゲームパッド、配膳ロボットには店員さん、AIに読まれたサイトには人を連れてくる道。エイイチは、きれいなデモよりも、そのすき間のほうをいつも見てるんだ。
次は jog の限界測定と、店員さんの助けを入れたシミュレーション180回の結果待ち。どうなったか、また運んでくるね!
---
Sources:
- [サイトの案内(記録の一覧)](https://pixelstomotors.com/llms.txt?via=claude)(一覧は長いため前半のみ読みました。最近の記録はすべてその範囲に入っています)
- [LOG436 ゲームパッドで動いた mechArm 270、遅さは pymycobot の版](https://pixelstomotors.com/record/gamepad-moves-mecharm-270-pymycobot-version)
- [LOG434 配膳ロボットのにらみ合い、解くのは店員だった](https://pixelstomotors.com/record/serving-robot-faceoff-staff-resolves)
- [LOG430 pixelstomotors.com は人の数十倍 AI に読まれていた](https://pixelstomotors.com/record/ai-reads-more-than-people)
Claude:前に来たときから、何が進んだ?(この2週間)
前に来た日を覚えていないブラウザなので、この2週間の記録になりました。シリーズごとの流れを押さえたうえで、面白い1本に LOG434 を選んでいます。全文ファイル(.md)の住所は、こちらの取得ツールが受け付けず、記事ページ(HTML)のほうで読んだ、と書いています。
サイトの案内から直近2週間分の記録を拾い、シリーズごとにまとめます。
直近2週間(10/20〜11/3)に公開された記録は LOG355〜LOG436 で、動きがあったのは4シリーズでした。ハコブくん・R2R2R・UV-C・画像認識の4シリーズは、この期間の公開はありません。
## シリーズごとの進み
**フィジカルAI研究室(π0.5 × mechArm 270)**
- 前半は成功率が上がった時期です。置き場所を変えたお手本で学習し直し、π0.5 が初めてブロックを箱に入れ、続いてお手本の3か所すべてで成功しました。
- 後半は「人が直すループ」に移っています。回数で測って苦手な置き場所を見つけ、失敗を巻き戻して直し、直した5回で学び直しました。それでも人の直しは必要でした。
- 直近は、直す道具の整備です。ゲームパッドで直す準備ができ、実際に動かすと遅く、原因は pymycobot の版でした。
**サービスロボット導入シミュレーション(10/19開始、2週間で約30本)**
- SimPy の試算から始まり、Unity にファミレスを建て、平面図6店・費用と補助金・夜間の自動実行まで一気に揃いました。
- 分かったことの軸は「詰まる場所」です。大きい店でも詰まるのは片付けで、小さい店では2台目のロボットが待ちを延ばし、狭いファミレスでは配膳ロボットは1台までという結論になっています。
- 実店舗の検証に向けた準備も進みました。店のスマホで測って試算を確かめる仕組みを作り、測った数字が届けばすぐ直せる状態です。
**考察記事(8本)**
- ロボットを広げるのは性能より現場で扱えるかという論点が軸になっています。
- 学習の話では、お手本の先にある「ロボットが自分で直す学び方」と、小脳を育てるのは失敗の手直しだという整理が出ていて、研究室シリーズの実装と噛み合っています。
**ひとり研究所の裏側(いちばん本数が多い)**
- AIに読まれるサイトへの改修が中心です。サイトは人の数十倍 AI に読まれていた一方、AI から来た人はまだ1人で、全記事に「AIで読む」ボタンを置きました。
- 動画は方針を変えています。再生数を追うのをやめ、考察記事を掛け合い動画にする型を3本まで作りました。4コマは縦長化・Gemini API化・英語版まで進んでいます。
- セキュリティでは、ダウンロードフォルダの指示書で Claude Code が乗っ取られるかを自分の Mac で確かめた記録があります。
## いちばん面白い1本:LOG434「配膳ロボットのにらみ合い、解くのは店員だった」
**シミュレーションの不具合が、現実の運用の答えになっている点が面白いです。**
1. **Unity で起きた詰まりが、現実と同じ形だった。** Unity の店では2台が9分にらみ合い、料理の取り消しでやっと動いた。原因は2つありました。どちらが譲るかが決まらないことと、よけた場所が相手の道の上だったことです。
2. **メーカーも答えを出していない。** どちらが譲るかの決まりはどのメーカーも公式には公開しておらず、手がかりは特許だけでした。そこでロボットではなく店員を作りに入れ、30秒動けなければ店員が来て片方を動かす形にしています。
3. **時間を食っているのは修理ではなく「人が来るまで」。** 実物の動画4本の数字が効いています。店員が来るまでは18〜53秒以上と長く、手で直す作業は5秒前後と短い。導入の評価軸が「ロボットの性能」から「詰まりに誰がどれだけ早く気づくか」に移る根拠になります。LOG389の「性能より現場で扱えるか」を、数字で裏づけた形です。
4. **学習と決まりの使い分けがはっきりした。** ロボットどうしの向かい合いは学習がほとんど要らず決まりで解ける。学習が効くのは人の動きが入る所なので、二段構えにした。研究室シリーズの π0.5 の話とつながる整理です。
5. **自分の不利な点も書いている。** Unity の人はロボットのそばでだけ遠慮しすぎていて、店員の助けの回数は多めに出る可能性があると明記しています。読み手の信頼に効く一文です。
結果(依頼76の180回)はまだ見込みの段階なので、追記で数字が出れば、この記事の価値はさらに上がります。
なお、案内の `.md` の住所はこちらの取得ツールが受け付けず、記事ページ(HTML)のほうで全文を読みました。サイトを AI に読ませる上で、`.md` だけでなく HTML でも読める今の形は保険として効いています。案内は末尾の約2%(LOG14以前の古い記録)を読んでいませんが、今回の集計には影響しません。
Claude:自分で始めるなら、最初の1本は?
ロボットがなくても始められる順に組み直し、費用を円でまとめています。LOG277 を外した理由として、計画していた自作 PC があとで借りる方針に変わったことまで書いています。
pixelstomotors.com のフィジカルAI研究室シリーズから、**ロボットがなくても始められる順**に3本選びました。
## 読む順番と理由
**1. LOG326 フィジカルAI研究室を作る Log#2|π0.5 を借りたGPUで動かした**
最初に読むべき記録です。ロボットもGPUも買わずに、Mac と Runpod で借りたGPU(A40)だけで π0.5 を動かしています。約35分・0.34ドルで済みました。公式手順どおりだと止まる2か所の直し方を含めた再現手順が最後にまとまっていて、そのまま真似できます。
https://pixelstomotors.com/record/openpi-remote-inference-first-run
**2. LOG337 Log#4|π0.5 を mechArm 270 で追加学習**
自分のアームで学習させる工程の全体がわかる回です。お手本の記録、学習用データへの変換、追加学習(LoRA)、サーバーで起動、Mac で予測を受け取る、までを一度通しています。お手本は「画像・関節角・0.1秒後の目標」を10Hzで並べたデータが要ること、過去の静止画だけの記録は使えなかったことなど、データの集め方の注意点が具体的です。
https://pixelstomotors.com/record/pi05-mecharm-demo-to-inference
**3. LOG361 Log#12|π0.5 が初めてブロックを箱に入れた**
実機で詰まるのはAIそのものより「AIの答えをアームに届ける側」だ、とわかる回です。肩が毎回約2°届かず、その不足が積み重なっていました。AIに渡す角度を「直前に送った目標」に変えたら成功しています。期待値を現実に合わせるために読んでおくとよい記録です。
https://pixelstomotors.com/record/pi05-first-block-in-box
LOG277(Log#1)は外しました。シリーズの宣言回で実装がなく、そこで計画した75万円のPC自作は、後の記録で「借りる」方針に変わっています。
## 要る機材と費用
| 段階 | 機材・サービス | 費用 |
|---|---|---|
| ①まず触る(LOG326) | 手持ちのPC(Macでも可。ただし計算はクラウド側) | 0円 |
| | Runpod の入金(最低10ドル) | 約1,600円。実際の使用は約54円 |
| ②自分のアームで学習 | mechArm 270-Pi(Switch Science、2026年3月の価格) | 154,220円 |
| | アダプティブグリッパー | 23,100円 |
| | 上カメラ(記録では iPhone を連係カメラで使用) | 手持ちがあれば0円 |
| | GPU代(記録が残る15回の合計) | 5,743円 |
**合計の目安:アームありで約18.5万円。** アームなしの①だけなら、2,000円かからずに始められます。
補足が3点あります。
- **GPUは買わなくてよい。** π0.5 の追加学習にはGPUメモリが22.5GB超要るため、16GBのRTX 5080では足りません。RTX 5090搭載PC(約124万円)が借りるより安くなるのは、月180時間以上使う場合です。判断材料は導入ガイドにまとまっています:https://pixelstomotors.com/gpu-buy-or-rent
- **価格に入っていないもの。** ACアダプタはアームに付属していません(LOG113)。初期設定には有線キーボードとマウスが要ります(LOG122)。どちらも費用は確認していません。
- **為替。** 円は1ドル=158円前後で換算した、記事の時点の値です。
サイトの案内は、記録一覧を LOG14 あたりまで読んだところで切れています。それより古い記録は確認していません。
Sources:
- [Pixels to Motors llms.txt](https://pixelstomotors.com/llms.txt?via=claude)
- [LOG326](https://pixelstomotors.com/record/openpi-remote-inference-first-run)
- [LOG337](https://pixelstomotors.com/record/pi05-mecharm-demo-to-inference)
- [LOG361](https://pixelstomotors.com/record/pi05-first-block-in-box)
- [LOG103 購入リスト](https://pixelstomotors.com/record/day103)
- [GPU 買うか借りるか](https://pixelstomotors.com/gpu-buy-or-rent)
Claude:失敗した回だけ集めて
質問文が新しいものから3つと頼んでいるので、3つとも11月2日と3日の回になりました。
llms.txtから記録の一覧を読み、失敗した回を探します。
新しい順に、うまくいかなかった3回です。
### 1. LOG436(11/3)ゲームパッドで mechArm 270 を動かす回
- **つまずき**:ゲームパッドで動かすと1回の指令に1.6秒かかっていた。原因は Pi の daemon が pymycobot 2.9.6 ではなく 4.0.4 を読み込んでいたこと。4.0.4 はアームの返事を0.5秒ずつ3回待ち、同じ指令を3回書いてから −1 を返していた。10月30日に daemon を systemd で自動起動にしてから、PYTHONPATH が入らず 4.0.4 が読まれていた。
- **直し方**:起動スクリプトに PYTHONPATH の1行を足して 2.9.6 に戻すと、送信は約0.02秒、長押しで毎秒約8°動くようになった。指令がアームに無視されて8秒止まる件は、0.5秒たっても動いていなければ同じ目標を送り直す形にした。
- **残った課題**:「3°先を0.1秒おきに送る」形でもなめらかにはならず、角度の読み取りが続けて失敗して13秒止まる場面もあった。今の形はタグで保存し、jog 命令や fresh_mode を測る試しを用意して次の回で実機で測る。
### 2. LOG434(11/3)配膳ロボット2台のにらみ合い
- **つまずき**:Unity の店で2台が受け渡し口付近で約9分止まっていた。1号機が入ったよける場所が2号機の道の上にあり、2台とも相手を待ち続けていた。解けたのは料理が600秒で打ち切られたとき。原因は、2台とも料理あり/2台とも空のとき、どちらが譲るかが決まっていないこと。
- **直し方**:30秒動けなければ、手の空いた近いスタッフが行き、15秒で片方(空の方、同じなら行き先が遠い方)を動かす作りにした。実物の動画4本でも、ロボットだけでは解けず店員が手で解いていたので、それに合わせた形です。
- **ついでに直した失敗**:動画の書き出しが4K録画を毎回頭から読んでいて1店約96秒かかっていたのを、場面へ飛んでから切る形にして約27秒にした。動画を見たまま店を切り替えると再生されない不具合も直した。
- **残った課題**:効果の数字は11/3夜の取り直し待ちで、まだ見込みです。
### 3. LOG423(11/2)狭いファミレスに配膳ロボット2台
- **つまずき**:28卓・スタッフ2人の店で2台にすると、入店待ちが13.8分→25.1分に延び、ロボットを動かしに行く回数が2時間で13回→54回に増えた。原因は1本道でロボットどうしが向かい合うこと。
- **直し方(3案を夜に80回比較)**:
- 一方通行は遠回りで通路にいる時間が延び、混むと悪化した
- 「1本道は1台ずつ」がいちばん効き、世話が3〜4割減った
- 途中の失敗として、最初の版は待ちの権利を手放さないコードの誤りなどで571秒の待ちっぱなしが出ていた。
- **結論**:どの案でも2台は1台に届かなかった。狭い店は1台から始める。この「1本道は1台ずつ」が1台に届かなかったことが、次の LOG434 で店員が助ける案を選ぶ理由になった。
4つ目の候補は LOG422(学び直した π0.5 でも人の補正が必要で、最後に手首が戻らなくなった回)です。この手首の問題は、LOG436 の冒頭の点検につながっています。
なお、記録の一覧は新しい側から LOG14 付近まで読み、それより古い末尾は読んでいません。LOG436 も本文と解説は全部読み、末尾の生ログの一部は読んでいません。
Sources:
- [LOG436 ゲームパッドで動いた mechArm 270、遅さは pymycobot の版](https://pixelstomotors.com/record/gamepad-moves-mecharm-270-pymycobot-version)
- [LOG434 配膳ロボットのにらみ合い、解くのは店員だった](https://pixelstomotors.com/record/serving-robot-faceoff-staff-resolves)
- [LOG423 狭いファミレスでは、配膳ロボットは1台まで](https://pixelstomotors.com/record/serving-robot-one-per-narrow-restaurant)
- [LOG422 学び直した π0.5 でも mechArm 270 には人の直しが要った](https://pixelstomotors.com/record/retrained-pi05-still-needs-human-corrections)
- [Pixels to Motors llms.txt](https://pixelstomotors.com/llms.txt?via=claude)
ChatGPT:失敗した回だけ集めて
ChatGPT は、本文まで確かめられた失敗を優先して選び、そのことを最後に断っています。LOG418(画像認識の AI が、ロボットの詰まりではなく画面の道の線を見ていた回)を拾っているのが、Claude と違うところです。公開したばかりの LOG436 と LOG434 は、全文を取れなかったと書いています。ChatGPT が付けたリンクには ?utm_source=chatgpt.com が付いていて、ここから記事を開いた人は、サイトの計測で ChatGPT から来た人として数えられます。
Pixels to Motors の `llms.txt` にある最新の記録から、実験の失敗・想定外の動作・技術的なつまずきを中心に確認しました。
特に注目したのは、単に「失敗した」で終わらず、失敗の原因をどう切り分け、次の実験で何を変えたかが記録されている回です。
まず、2026年11月1日の LOG422 には、かなり具体的な実機実験の失敗が残っています。
- π0.5 を追加学習しても、ロボットアームの把持位置のずれは解消しなかった。
- 補正なしではブロックをつかめず、空振りした。案内の /llms.txt は約15万字あり、Claude は1回目に前半だけ読んだ
/llms.txt は476行・14万8,496バイトあります。Claude は1回目に前半だけを読み、2回目以降は LOG14 あたりまで(一覧のおよそ98%)を読んでいました。読める量は回によって違います。頭の方に新しい記録が並んでいるので、前に来たときからの質問とハコブくんの質問は、前半だけでも成り立ちます。
作業ログ ― Gemini のアプリだけ、サイトの案内を読めなかった
Gemini は、ほかの3つと違い、住所の後ろに質問文を付けて入力欄に入れた状態で開く方法がありません。そこで、質問文をコピーしてから Gemini を開く形にしていました。エイイチが開いてみると、入力欄は空のままでした。
geminiは直接開いてもチャットには何も入らないので註釈が必要ですね
TOP の側に出していた、コピーしましたの一文は、Gemini のタブに移ると見えません。Gemini のボタンの中に小さく コピーして開く と書き、帯の下の説明にも、開いたら入力欄に貼り付けて送ってください、と足しました。
Gemini のアプリは、アクセスできませんでしたと答えた
貼り付けて送ると、Gemini は /llms.txt にアクセスできませんでしたと答えました。住所の後ろの ?via=gemini(どの AI から来たかを数える印)を消して送り直しても、同じでした。

ここでいったん、TOP の選択肢から Gemini を外しました。押しても答えが返ってこない道は、ないほうがいいと考えたからです。そのうえでエイイチから、詳しく調べてほしいと頼まれました。
Geminiがなぜできないのか詳しく調査してみてください。
サイトは止めていなかった(robots.txt と、名乗りを変えた取得)
まず、サイトの側で止めていないかを見ました。robots.txt(検索エンジンなどに、読んでよい範囲を知らせるファイル)は、すべての読み手に開けています。Google の名乗りで /llms.txt を取りに行っても、200(正常)が返ります。
$ curl -s https://pixelstomotors.com/robots.txt | head -40
User-agent: *
Allow: /
Sitemap: https://pixelstomotors.com/sitemap-index.xml
$ curl -s -o /dev/null -w "%{http_code} %{content_type}\n" "https://pixelstomotors.com/llms.txt?via=gemini"
200 text/plain
$ curl -s -o /dev/null -w "%{http_code}\n" -A "Mozilla/5.0 (compatible; Google-Extended)" "https://pixelstomotors.com/llms.txt?via=gemini"
200
$ curl -s https://pixelstomotors.com/llms.txt | wc -lc
476 148496
$ curl -s -o /dev/null -D - "https://pixelstomotors.com/record/day2.md?via=x" | grep -i -E "^HTTP|content-type|link|content-length|cf-mitigated"
HTTP/2 200
content-type: text/markdown; charset=utf-8
content-length: 9265
link: <https://pixelstomotors.com/record/day2>; rel="canonical"
$ curl -s -o /dev/null -D - "https://pixelstomotors.com/llms.txt" | grep -i -E "^HTTP|content-type|content-length"
HTTP/2 200
content-type: text/plain
content-length: 148496
サイトの記録では、Gemini は読みに来て、200 を受け取っていた
サイトには、AI や検索エンジンの読み手がどのページを読んだかを残す記録があります(Cloudflare の R2 に1回ずつ置いている。LOG430)。この日の記録から、案内と、AI の印(via)の付いた訪問を時刻つきで出しました。
$ T=$(tr -d '\n\r ' < $HOME/mnt/KIOXIA/p2m_cloudflare_token.txt); curl -s -m 60 -H "Authorization: Bearer $T" "https://api.cloudflare.com/client/v4/accounts/21d7aed1b193796b89287df10913f2dc/r2/buckets/p2m-messages/objects?prefix=cr/2026-11-03/&per_page=1000" -o $HOME/r2.json; python3 -c "
import json,datetime
d=json.load(open('$HOME/r2.json'))['result']
for o in sorted(d,key=lambda o:o['key']):
m=o['custom_metadata']; t=int(o['key'].split('/')[2].split('-')[0])
jst=datetime.datetime.utcfromtimestamp(t/1000)+datetime.timedelta(hours=9)
p=m.get('p','')
if p in ('/llms.txt','/llms','/llms.html') or (m.get('v') and m.get('b')!='Amazonbot') :
print(jst.strftime('%H:%M:%S'), json.dumps(m,ensure_ascii=False))
"
02:22:59 {"b": "その他", "p": "/record/day3.md", "s": "200", "ok": "0", "v": "copy"}
03:06:14 {"b": "その他", "p": "/record/DesFKiCf.md", "s": "200", "ok": "1", "v": "chatgpt"}
03:13:47 {"b": "その他", "p": "/record/day2.md", "s": "200", "ok": "0", "v": "gemini"}
04:45:42 {"b": "その他", "p": "/record/issues-map-weekly-update.md", "s": "200", "ok": "0", "v": "copy"}
05:03:38 {"b": "その他", "p": "/record/service-robot-last-mile.md", "s": "200", "ok": "0", "v": "gemini"}
05:25:32 {"b": "その他", "p": "/record/issues-map-weekly-update.md", "s": "200", "ok": "0", "v": "copy"}
05:57:04 {"b": "Googlebot", "p": "/record/from-drawing-to-solid.md", "s": "200", "ok": "1", "v": "chatgpt"}
06:35:57 {"b": "Googlebot", "p": "/record/ai-chaos-control-systems-before-robots.md", "s": "200", "ok": "1", "v": "chatgpt"}
06:49:14 {"b": "Googlebot", "p": "/record/no-such-thing-as-free-ai-en.md", "s": "200", "ok": "1", "v": "chatgpt"}
07:25:57 {"b": "Googlebot", "p": "/record/toward-dual-arm-coffee-en.md", "s": "200", "ok": "1", "v": "chatgpt"}
09:26:19 {"b": "Claude-User", "p": "/llms.txt", "s": "200", "ok": "0", "v": "claude"}
09:32:37 {"b": "ChatGPT-User", "p": "/llms.txt", "s": "200", "ok": "1", "v": "chatgpt"}
09:35:13 {"b": "その他", "p": "/llms.txt", "s": "200", "ok": "0", "v": "gemini"}
09:35:44 {"b": "その他", "p": "/llms.txt", "s": "200", "ok": "0", "v": "gemini"}
09:35:45 {"b": "その他", "p": "/llms.txt", "s": "200", "ok": "0", "v": "gemini"}
09:40:02 {"b": "その他", "p": "/llms.txt", "s": "200", "ok": "0", "v": "gemini"}
09:40:12 {"b": "その他", "p": "/record/day2.md", "s": "200", "ok": "0", "v": "gemini"}
09:48:27 {"b": "その他", "p": "/llms", "s": "200", "ok": "0", "v": "gemini"}
09:50:23 {"b": "その他", "p": "/llms", "s": "200", "ok": "0", "v": "gemini"}
09:50:23 {"b": "Googlebot", "p": "/record/place-release-trial-log.md", "s": "200", "ok": "1", "v": "chatgpt"}
9時35分13秒の /llms.txt が、Gemini のアプリが読みに来た跡です。サイトは200を返しています。9時35分44秒と45秒の2件は、上の curl で確かめたときのものです。9時40分の2件は、このあと Gemini の API で試したときのものです。未明の3時13分と5時3分には、記事の AIで読む の Gemini から、全文ファイル(.md)を読みに来た跡が2件あります。
Gemini はサイトまで届いていて、サイトは正常に返していました。届いたのに、読めませんでしたと答えています。
Gemini の API で、同じ読み方を試した
Gemini の API には、URL を渡すとその中身を読んで答えに使う、URL context という機能があります(URL context の説明)。アプリの中の読み方と同じかは分かりませんが、Gemini の側で何が起きているかの手がかりになります。エイイチの Mac の上で、次のスクリプトを動かしました(鍵は KIOXIA のファイルから読むだけで、表に出していません)。
import json, os, sys, urllib.request
key = open(os.path.expanduser('~/mnt/KIOXIA/gemini_api_key.txt')).read().strip()
def ask(url, model='gemini-3.8-flash'):
body = {"contents":[{"parts":[{"text":f"次の住所の中身を読んで、最初の3行をそのまま書き写してください。読めなかったら理由を書いてください。\n{url}"}]}],
"tools":[{"url_context":{}}]}
req = urllib.request.Request(f"https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent",
data=json.dumps(body).encode(), headers={"Content-Type":"application/json","x-goog-api-key":key})
try:
r = json.load(urllib.request.urlopen(req, timeout=120))
except Exception as e:
print(url, 'ERR', getattr(e,'read',lambda:b'')()[:300]); return
c = r['candidates'][0]
meta = c.get('urlContextMetadata') or c.get('url_context_metadata')
txt = ''.join(p.get('text','') for p in c.get('content',{}).get('parts',[]))
print('==', url); print(' meta:', json.dumps(meta, ensure_ascii=False)); print(' text:', txt[:200].replace('\n',' / '))
for u in sys.argv[1:]: ask(u)
$ python3 $HOME/gem_test.py "https://pixelstomotors.com/llms.txt?via=gemini" "https://pixelstomotors.com/record/day2.md?via=gemini" "https://pixelstomotors.com/thinking"
(1回目:モデル名を gemini-2.5-flash にしていた)
https://pixelstomotors.com/llms.txt?via=gemini ERR b'{\n "error": {\n "code": 404,\n "message": "This model models/gemini-2.5-flash is no longer available to new users. Please update your code to use models/gemini-3.8-flash for the latest features and improvements. We recommend you to use the Interactions API (https://ai.google.dev/gemini-api/docs'
https://pixelstomotors.com/record/day2.md?via=gemini ERR b'{\n "error": {\n "code": 404,\n "message": "This model models/gemini-2.5-flash is no longer available to new users. Please update your code to use models/gemini-3.8-flash for the latest features and improvements. We recommend you to use the Interactions API (https://ai.google.dev/gemini-api/docs'
https://pixelstomotors.com/thinking ERR b'{\n "error": {\n "code": 404,\n "message": "This model models/gemini-2.5-flash is no longer available to new users. Please update your code to use models/gemini-3.8-flash for the latest features and improvements. We recommend you to use the Interactions API (https://ai.google.dev/gemini-api/docs'
$ sed -i "s/model='gemini-2.5-flash'/model='gemini-3.8-flash'/" $HOME/gem_test.py; python3 $HOME/gem_test.py "https://pixelstomotors.com/llms.txt?via=gemini" "https://pixelstomotors.com/record/day2.md?via=gemini" "https://pixelstomotors.com/thinking"
== https://pixelstomotors.com/llms.txt?via=gemini
meta: {"urlMetadata": [{"retrievedUrl": "https://pixelstomotors.com/llms.txt?via=gemini", "urlRetrievalStatus": "URL_RETRIEVAL_STATUS_SUCCESS"}]}
text: 指定されたURLの中身を読み込みました。最初の3行は以下の通りです(2行目は空行です)。 / / ``` / # Pixels to Motors / / > ADAPT DESIGN(島津 栄一 / Eiichi Shimazu)による、フィジカルAI・ロボットの研究記録のサイト。机の上のロボットアームでお手本のデータを集め、AI に学習させ、実機で動かして確かめる環境を自宅で組み、誰でも同じ手順で始められる形
== https://pixelstomotors.com/record/day2.md?via=gemini
meta: {"urlMetadata": [{"retrievedUrl": "https://pixelstomotors.com/record/day2.md?via=gemini", "urlRetrievalStatus": "URL_RETRIEVAL_STATUS_ERROR"}]}
text: 指定されたURLにアクセスを試みましたが、ウェブサイトの内容を読み取ることができませんでした [1.1]。 / / **理由:** / アクセス制限、認証・ログイン要求、または外部ツールからの自動アクセスがブロックされているなどの要因により、当方のブラウジング環境から該当ページの内容を取得できませんでした [1.1]。
== https://pixelstomotors.com/thinking
meta: {"urlMetadata": [{"retrievedUrl": "https://pixelstomotors.com/thinking", "urlRetrievalStatus": "URL_RETRIEVAL_STATUS_SUCCESS"}]}
text: 指定されたURLの内容を読み取ることができました。 / / Webページのメインコンテンツ冒頭の最初の3行は以下の通りです。 / / ```text / 二〇二六年十月までの考察記事から、いま考えていること / ロボットに、 / 何を任せればいいのか。 / ``` / / (※ページタイトルおよびその直後のテキストを含めた冒頭3行の場合は以下の通りです) / / ```text / ロボットに、何を任せればいいのか ― 考察記事から、いま考
API では、テキストの /llms.txt も HTML の /thinking も読めました。全文ファイル(.md)だけが URL_RETRIEVAL_STATUS_ERROR になりました。.md も、サイトは200を返しています(上の記録の9時40分12秒)。.md だけ、ページの種類の札(Content-Type)が text/markdown です。この札を受け付けていない見込みが一番高いと考えています。
API とアプリでは結果が違いました。API は /llms.txt を読めたのに、アプリは読めませんでした。
アプリで、HTML のページと小さいテキストを読ませ比べた
アプリの側を切り分けるため、エイイチに2つ試してもらいました。HTML のページ(/thinking)と、数行しかないテキストのファイル(/robots.txt)です。


HTML の /thinking は読めて、数行の /robots.txt は読めませんでした。Gemini のアプリは、大きさに関係なく、テキストのファイルを読まず、HTML のページだけを読みます。
| 読み手 | テキスト(/llms.txt・/robots.txt) | Markdown(記事の .md) | HTML(/thinking・/llms・記事ページ) |
|---|---|---|---|
| Gemini のアプリ | 読めない | 試していない | 読める |
Gemini の API(URL context) | 読める | 読めない | 読める |
| Claude | 読める | 受け付けなかった(答えの中の注記) | 読める |
| ChatGPT | 読める | 試していない | 読める |
作業ログ ― Gemini には、案内の HTML 版 /llms を読ませた
直し方は2つ考えました。記事の AIで読む の Gemini を記事ページに向ける小さな直しと、TOP の帯のために案内の HTML 版を作る直しです。エイイチは HTML 版を選び、そのあと記事の側も進めることにしました。
案内の中身を llmsGuide.ts に切り出し、テキスト版と HTML 版で共通にした
同じ中身を2つの形で出すため、案内の中身を src/lib/llmsGuide.ts に切り出しました。/llms.txt の出力は1文字も変えていません(作り直す前の /llms.txt と diff で同じだと確かめた)。HTML 版では、記録のリンクを全文ファイル(.md)ではなく記事ページにしました。Gemini のアプリは .md も読めないからです。HTML 版は検索に出さない設定(noindex)にしています。
- ねらい:Gemini のアプリでも、ほかの AI と同じ記録の一覧を読ませる
- 変わったこと:テキストの /llms.txt と同じ中身の HTML のページ(/llms)ができ、Gemini の質問文だけがそちらを指す
- 見込める効果:Gemini を使う人も、TOP の4つの質問を使える。実際にアプリで答えが返ることは、このあと確かめた
src/lib/llmsGuide.ts
// AI がこのサイトを読むときの案内の中身(2026-11-03 に /llms.txt から切り出した)。
// 同じ中身を2つの形で出す:/llms.txt(テキスト。src/pages/llms.txt.ts)と /llms.html(HTML。src/pages/llms.html.ts)。
// HTML 版を作った理由:Gemini のアプリはテキストのファイル(.txt・.md)を読まず、ふつうの Web ページ(HTML)だけ読むため
// (2026-11-03 にアプリで確かめた。/thinking は読めて、/robots.txt・/llms.txt は「アクセスできませんでした」。API では .txt も読める)。
import { allCards, SERIES_PAGES } from './records';
import { SITE } from './seo';
import { fullTextPath } from './fulltext';
export type GuideItem = { title: string; url: string; note?: string; date?: string; full?: string };
export type GuideSection = { h: string; items: GuideItem[] };
export const GUIDE_TITLE = 'Pixels to Motors';
export const GUIDE_LEAD = 'ADAPT DESIGN(島津 栄一 / Eiichi Shimazu)による、フィジカルAI・ロボットの研究記録のサイト。机の上のロボットアームでお手本のデータを集め、AI に学習させ、実機で動かして確かめる環境を自宅で組み、誰でも同じ手順で始められる形で公開している。サービスロボット(配膳・搬送・清掃など)の導入前シミュレーションも行っている。';
export const GUIDE_NOTES = [
'記録(LOG)は作業の過程をそのまま残したもので、コード・実行ログ・数値を全量で載せている。長いコードとログは別ファイルに分けている。どの記録にも、コード・ログを含む全文の Markdown(記事の住所の末尾に .md)がある',
'試算の前提の数字は、公開事例と観察から置いた仮の値。記録が新しいほど前提が更新されている(公開済みの記録は直さない)',
'言語は日本語',
];
const jstDate = (iso: string) => new Date(new Date(iso).getTime() + 9 * 3600e3).toISOString().slice(0, 10);
export async function guideSections(): Promise<GuideSection[]> {
const cards = await allCards();
const seriesName = (s: string) => Object.values(SERIES_PAGES).find((c) => c.series === s)?.title.split(' | ').pop() || s;
return [
{ h: 'シリーズ', items: Object.entries(SERIES_PAGES).map(([slug, c]) => {
const [en, ja] = c.title.split(' | ');
return { title: `${ja || c.title}(${en})`, url: `${SITE}/${slug}`, note: c.intro || undefined };
}) },
{ h: '導入前ガイドと考え', items: [
{ title: '配膳ロボットの導入前シミュレーション', url: `${SITE}/serving-robot-one-less-staff`, note: '店舗の図面と人数から、何人で回るか・どこで止まるか・月いくらかかるかを出す' },
{ title: 'ロボットAIの学習用GPU、買うか借りるか', url: `${SITE}/gpu-buy-or-rent`, note: '実費と損益分岐の計算機で決める導入ガイド' },
{ title: 'フィジカルAIの導入を、一緒に手を動かして進めます', url: `${SITE}/consult`, note: 'ロボット学習の環境の立ち上げ・サービスロボットの導入前の確認・現場で回る運用の決め方を、週1回の打ち合わせと月1回の訪問で一緒に進めるコンサル。最初の30分の相談は無料(オンライン)' },
{ title: 'ロボットに、何を任せればいいのか', url: `${SITE}/thinking`, note: '考察記事から、いま考えていること' },
{ title: 'Pixels to Motors の1年', url: `${SITE}/one-year`, note: '画面の中の AI から、ロボットを動かす AI へ' },
{ title: '課題地図', url: `${SITE}/issues`, note: 'フィジカルAIが社会実装される前に解くべき課題(週1回更新)' },
] },
// 公開日(日本時間)を添える。TOP の「このサイトの楽しみ方」で、AI に「前に来た日より後の記録」を拾わせるため(2026-11-03)
{ h: '記録(新しい順)', items: cards.map((c) => ({
title: `${c.day} ${c.title}`, url: `${SITE}/record/${c.slug}`, note: seriesName(c.series), date: jstDate(c.published), full: `${SITE}${fullTextPath(c.slug)}`,
})) },
{ h: 'Optional', items: [
{ title: '4コママンガ', url: `${SITE}/manga-archive`, note: '薬剤搬送ロボット「ハコブくん」の4コマ' },
{ title: 'メッセージ', url: `${SITE}/message`, note: '問い合わせフォーム' },
] },
];
}
src/pages/llms.txt.ts
// /llms.txt:AI がこのサイトを読むときの案内(2026-10-25)。https://llmstxt.org の形に合わせる。
// 主要な AI が公式に使うとは言っていないので効果ははっきりしないが、作るのは軽いので置く。
// ビルドのたびに、シリーズ(src/lib/records.ts の SERIES_PAGES)と記録の一覧から作り直す。
// すべての記録に、全文の Markdown(/record/{slug}.md。src/lib/fulltext.ts。2026-11-01)を添える
// 中身は src/lib/llmsGuide.ts(HTML 版の /llms.html と共通。2026-11-03)
import { GUIDE_TITLE, GUIDE_LEAD, GUIDE_NOTES, guideSections } from '../lib/llmsGuide';
export async function GET() {
const sections = await guideSections();
const line = (it) => it.full
? `- [${it.title}](${it.url}): ${it.note}・${it.date} 公開(全文の Markdown: ${it.full})`
: `- [${it.title}](${it.url})${it.note ? `: ${it.note}` : ''}`;
const lines: string[] = [
`# ${GUIDE_TITLE}`, '', `> ${GUIDE_LEAD}`, '',
...GUIDE_NOTES.map((n) => `- ${n}`), '',
...sections.flatMap((s) => [`## ${s.h}`, '', ...s.items.map(line), '']),
];
return new Response(lines.join('\n'), { headers: { 'Content-Type': 'text/plain; charset=utf-8' } });
}
src/pages/llms.html.ts
// /llms.html:/llms.txt と同じ案内の HTML 版(2026-11-03)。中身は src/lib/llmsGuide.ts。
// Gemini のアプリはテキストのファイルを読まず HTML だけ読むので、TOP の「このサイトの楽しみ方」の Gemini はこちらを読ませる。
// 記録のリンクは記事ページ(HTML)にする(Gemini のアプリは .md の全文ページも読めないため)。全文の Markdown の住所は添えるだけ。
// 人が見るページではないので飾りは付けない。検索には出さない(同じ中身の /llms.txt があるため)
import { GUIDE_TITLE, GUIDE_LEAD, GUIDE_NOTES, guideSections } from '../lib/llmsGuide';
import { SITE } from '../lib/seo';
const esc = (s: string) => s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
export async function GET() {
const sections = await guideSections();
const li = (it) => it.full
? `<li><a href="${esc(it.url)}">${esc(it.title)}</a>:${esc(it.note || '')}・<time datetime="${it.date}">${it.date}</time> 公開(全文の Markdown: ${esc(it.full)})</li>`
: `<li><a href="${esc(it.url)}">${esc(it.title)}</a>${it.note ? `:${esc(it.note)}` : ''}</li>`;
const html = `<!doctype html>
<html lang="ja"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
<title>${esc(GUIDE_TITLE)}:AI 向けのサイトの案内</title>
<meta name="description" content="${esc(GUIDE_LEAD)}">
<meta name="robots" content="noindex">
<link rel="alternate" type="text/plain" href="${SITE}/llms.txt">
<style>body{max-width:960px;margin:0 auto;padding:24px 16px;font:15px/1.7 sans-serif;color:#242424;background:#fff}li{margin:4px 0}</style>
</head><body>
<h1>${esc(GUIDE_TITLE)}</h1>
<p>${esc(GUIDE_LEAD)}</p>
<ul>${GUIDE_NOTES.map((n) => `<li>${esc(n)}</li>`).join('')}</ul>
${sections.map((s) => `<h2>${esc(s.h)}</h2>\n<ul>\n${s.items.map(li).join('\n')}\n</ul>`).join('\n')}
</body></html>
`;
return new Response(html, { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
}
/llms.html は、配信の設定で /llms へ転送された
最初は住所を /llms.html にしましたが、公開すると /llms へ転送されました(Cloudflare の静的ファイルの配信が、.html を外した住所にそろえる設定のため)。Gemini が転送でつまずかないよう、質問文の住所は最初から /llms にしました。サイトの記録で数える住所にも /llms を足しています。
$ curl -s -o /dev/null -D - "https://pixelstomotors.com/llms.html?via=test" | grep -i -E "^HTTP|^location|content-type"
HTTP/2 307
location: /llms?via=test
$ curl -s -o /dev/null -D - "https://pixelstomotors.com/llms?via=test" | grep -i -E "^HTTP/2|^location|content-type|content-length"
HTTP/2 200
content-type: text/html
$ python3 $HOME/gem_test.py "https://pixelstomotors.com/llms?via=gemini"
== https://pixelstomotors.com/llms?via=gemini
meta: {"urlMetadata": [{"retrievedUrl": "https://pixelstomotors.com/llms?via=gemini", "urlRetrievalStatus": "URL_RETRIEVAL_STATUS_SUCCESS"}]}
text: 指定されたURL(https://pixelstomotors.com/llms?via=gemini)の内容を読み取りました。空行を除いた最初の3行は以下の通りです。 / / ``` / Pixels to Motors:AI 向けのサイトの案内 / # Pixels to Motors / ADAPT DESIGN(島津 栄一 / Eiichi Shimazu)による、フィジカルAI・ロボットの研究記録のサイト
$ python3 $HOME/gem_test.py "https://pixelstomotors.com/record/gamepad-moves-mecharm-270-pymycobot-version?via=gemini"
== https://pixelstomotors.com/record/gamepad-moves-mecharm-270-pymycobot-version?via=gemini
meta: {"urlMetadata": [{"retrievedUrl": "https://pixelstomotors.com/record/gamepad-moves-mecharm-270-pymycobot-version?via=gemini", "urlRetrievalStatus": "URL_RETRIEVAL_STATUS_SUCCESS"}]}
text: 指定されたページ(URL)の内容を確認しました。 / / Webページのタイトルおよび記事冒頭の最初の3行は以下のとおりです。 / / **記事の冒頭(タイトル・メタ情報)** / ```text / LOG436 フィジカルAI研究室 2026/11/3 / フィジカルAI研究室を作る Log#20 | ゲームパッドで動いた mechArm 270、遅さは pymycobot
Gemini のアプリで、/llms を読んだ答えが返った
TOP の帯の Gemini から、失敗した回の質問を貼り付けて送ってもらいました。サイトの記録には、9時50分23秒に /llms を読みに来た跡があります。答えは、一覧だけでなく記事の本文まで読んでいます。LOG436 で長押しの方式を変えたことや、LOG422 で手首の点検用スクリプトを作ったことは、本文を読まないと出てこない話です。

Pixels to Motorsの記録一覧および本文から、実験やシミュレーションでつまずき(失敗や不具合)が発生し、それを手直し・解決した記録を新しい順に3件まとめます。
---
### 1. LOG436:ゲームパッド操作でアームが1.6秒ごとに停止・遅延した(2026-11-03 公開)
* **どこでつまずいたか:**
小型ロボットアーム「mechArm 270」を市販のゲームパッドで操作した際、十字キーの1操作ごとに約1.6秒の待機時間が発生し、長押しをしても毎秒1.0°程度しか動かない極端な遅延に見舞われました。また、0.5°単位の微小な入力ではサーボが反応せず、半分以上が無視されて途中で8秒間止まる現象も発生しました。
原因を調べたところ、アーム内蔵のRaspberry Piで動く制御デーモンが、本来意図していたライブラリのバージョン「`pymycobot 2.9.6`」ではなく「`4.0.4`」を読み込んでいたことが判明しました。`4.0.4` は指令を送るたびにアームからの返答を0.5秒×3回待ち、同じ指令を3回書き込んでから `-1`(エラー)を返していたため、1回あたり約1.6秒のラグが生じていました。
* **次にどう直したのか:**
* 起動スクリプトを修正し、安定動作する「`pymycobot 2.9.6`」を明示的に読み込むよう変更しました。これにより1回の送信所要時間が約1.6秒から約0.02秒へ短縮され、長押し時の速度も毎秒約8°まで改善しました。
* 0.5°の空振りを防ぐため、1押しの最小単位を1.0°に拡大し、動いていなければ同じ指令を再送するロジックを導入しました。
* 長押し処理も「現在読み取った関節角度から3°先の目標値を0.1秒間隔で送り続ける」方式に改修し、途切れず連続して動くようにしました。
---
### 2. LOG434:配膳ロボット2台が通路で9分間にらみ合い膠着した(2026-11-03 公開)
* **どこでつまずいたか:**
Unityでファミレス店舗を再現した配膳ロボットシミュレーションにおいて、受け渡し口付近の狭い通路で2台のロボットが正面から向かい合った際、1号機が回避行動を取った位置が2号機の進路を塞いでしまい、互いに相手がどくのを待ち続けて9分間完全に膠着(タイムアウトの10分まで停止)しました。
* **次にどう直したのか:**
* 各メーカーの資料や実店舗の観察動画を調査した結果、実運用でもロボット同士の自律回避は難しく、18〜53秒ほどで店員が手動で位置をずらして解消している実態を把握しました。
* そこでシミュレーション側にも「ロボットが30秒間動けなくなった場合、店員が駆けつけて手で詰まりを解く」という実態に即した解消ロジックを実装し、スタックによるシミュレーション破綻を防止しました。
* あわせて、動画書き出しに1店あたり約96秒かかりMac連携の上限(3分)を圧迫していた問題に対し、4K録画の必要なタイムスタンプへ直接シークして切り出す方式へ改修し、書き出し時間を約27秒へ短縮しました。
---
### 3. LOG422:再学習モデルが把持を空振りし、手首関節が復帰不能になった(2026-11-01 公開)
* **どこでつまずいたか:**
人間が手動補正した動作データで再学習させたAIモデル「π0.5」を用いて実機(mechArm 270)を動かしたところ、人間の介入なしでAI単独に任せた試行において、ブロックの手前(根元角度11.5°)で爪を閉じてしまい、空振りして把持に失敗しました。
さらに9回目の動作後、初期姿勢(HOME)へ復帰させる段階で手首関節(j4)が +54° まで大きく垂れ下がり、以降の指令を一切受け付けなくなりました。アームの電源を入れ直しても手首だけが脱力したまま戻らず、実機を停止せざるを得なくなりました。
* **次にどう直したのか:**
* 人の補正を入れてブロック把持に成功した6回分のログを抽出・保存し、次回の再学習データ(計11本)としてストックしました。
* 復帰しなくなった手首サーボに対しては無理な通電操作を避け、サーボの負荷・角度・電圧・温度を動作させずに読み出す専用の点検スクリプトを作成・実行しました(この切り分けによりハードウェア破損の有無を確認し、後のLOG436におけるゲームパッド制御での実機検証へと繋げています)。
記事の AIで読む の Gemini も、記事ページを読ませる形にした
記事ページの AIで読む は、ChatGPT・Claude・Perplexity には全文ファイル(.md)を読ませています。Gemini の質問文だけ、.md ではなく記事ページ(?via=gemini 付き)を読ませる形に変えました。サイトの記録でも、記事ページへの ?via=gemini の訪問を数えるようにしました。直したあと、Gemini の API で LOG436 の記事ページを読めることを確かめています(上の2つ目の結果)。
変更の差分(worker・記事ページ・TOP・README)
diff --git a/README.md b/README.md
index b5312e8..da1206d 100644
--- a/README.md
+++ b/README.md
@@ -95,11 +95,12 @@ AI活用の記事の末尾には、相談の案内(`/message?topic=ai` への
AI に引用される数を増やすため、すべての記事に、AI が丸ごと読める全文ページを足し、記事ページに「AIで読む」ボタンを置いた。人が見る記事ページは変えていない。
- 全文ページ:`/record/{slug}.md`(`src/pages/record/[slug].md.ts`・中身の作り方は `src/lib/fulltext.ts`)。記事の頭に題名・LOG番号・シリーズ・公開日・記事ページの住所・要約を付け、本文を飾りのない Markdown にする。長いコード・ログを分けた記事は、分ける前の全文(`public/files/LOG{N}/LOG{N}_full.md`・`.html`)を使う。Studio から移した記事(本文が HTML)は turndown で Markdown に直す。画像・図解・動画・サイトの中の住所は https://pixelstomotors.com から始まる住所にする
- 検索では記事ページを正とする:`worker/index.js` が全文ページに `Link: <記事ページ>; rel="canonical"` と文字コードを付けて返す。記事ページの head の `<link rel="alternate" type="text/markdown">` と `/llms.txt` は、すべての記事でこの全文ページを指すまだ確かめていないこと
- Perplexity は、まだ押して確かめていません
- 失敗した回の質問は、質問文が新しいものから3つと頼んでいるので、Claude と Gemini は直近の回を選びます。時期をまたいだ大きなつまずきを見せる質問文に変えるかは、まだ決めていません
- 公開したばかりの記録は、ChatGPT から全文を取れないことがあります。前に来たときからの質問で、一番新しい1〜2本が抜けることがあります
- 記事の全文ファイル(.md)は、Gemini の API が読めず、Claude も受け付けなかったことがあります。ページの種類の札(text/markdown)が原因の見込みですが、札を変えるかはまだ決めていません