# 机器人小脑 Web v0.8.0
独立浏览器原型;真实像素模板跟踪 + 传感器证据驱动状态机。默认执行器是明确标注的合成演示,不含硬件驱动,不是物理仿真器,也不能作为真实机器人安全控制器。
## 手机快速使用
打开部署后的 HTTPS 地址,点击「开启摄像头」,允许浏览器相机权限。默认后置优先,可切换前/后置;不请求麦克风。手指拖动框选一个对比明显、有纹理、尺寸稳定的目标。点抓取/放置会演示合成传感器反馈,并不会让画面中的真实物体移动。Safari/Chrome 的实际相机权限与兼容性需在用户设备验证。应用内嵌浏览器若禁止摄像头,请在系统浏览器打开。相机帧默认不上传。
## 运行 / 部署
- Node 20+,没有应用运行依赖
- `npm test` 单元与桥接逻辑测试
- `npm start` 启动本地 http://localhost:4173(仅静态前端)
- `node build.mjs` 生成 `worker/assets.js` 和无 npm 依赖的 `worker/bundle.js`
- 已有授权 Cloudflare 环境可用 Wrangler `npx wrangler deploy`,或通过 Cloudflare Worker 上传 API 发布 bundle;首次部署 SQLite Durable Object migration v1 / Room,绑定名 ROOMS
- 不需要第三方 API key,不含持久凭据。既有 Workers 不会被修改。线上资源受账户原有 Cloudflare 计费规则影响;本项目不升级套餐、不设置付费 TURN
## 模块
`dist/core.js`: Tracker + Cerebellum。`dist/app.js`: 相机/视频/触摸交互。`dist/transport.js`: WebRTC 优先与 WS 回退。`dist/protocol.js`: 二进制图像协议。`dist/simulator.*`: 合成远端发送与反馈夹具。`worker/index.js`: 公开静态资源 + 按临时房间隔离的中继。`tests`: Node 测试。
## 本地集成 API
页面提供 `window.cerebellum`,版本 0.8.0,也可直接 import Cerebellum 独立实例。
```
const api = window.cerebellum;
api.ingestFrame({frameId:'sim-001',timestamp:performance.now(),
width:320,height:200,data:imageData.data});
api.retainReference('sim-001'); // 云端决策或拖动可能延迟时先保留,4帧/60秒上限
api.selectTarget({frameId:'sim-001',bbox:{x:40,y:40,width:40,height:30},
requestId:crypto.randomUUID()});
api.addEventListener('actionRequest', ({detail:a}) => {
// a.state / a.commandId / a.session / a.requestId / a.bbox / a.destination
// 将符号动作交给自己的仿真器;必须配置自己的坐标标定与执行器约束
});
api.grasp({requestId:crypto.randomUUID()});
// 必须使用动作当前的 session / commandId,sequence 单调递增
api.ingestSensor({session:1,commandId:'1:1',sequence:1,
timestamp:performance.now(),atApproach:true});
api.place({requestId:crypto.randomUUID(),destination:{x:.4,y:.2,z:.1}});
api.stop(); // UI API 同时关闭相机/视频/桥接并废弃旧反馈
```
`ingestObservation` 是 `ingestSensor` 的别名。`snapshot` 读取状态。`reset` 清除请求去重历史。事件:tracking(bbox 像素坐标、confidence、status、frameId、processingMs)、actionRequest、state、result、feedbackRejected、reselectionRequired。框选 API 接收输入图像坐标,不是 CSS 像素。UI 固定缩放至 320×200;直接核心 API 支持至 640×480。将本地仿真图像直接传入核心,不经过 JPEG 或 Cloudflare;使用独立核心实例时应自行按 100ms 调用 tick,管理源生命周期。
### 动作证据与停止
approach 需要 atApproach;grip 需要 contact;verify 同时需要 contact/objectHeld;testLift 同时需要 objectHeld/lifted。只有试提通过才返回 grasp success 并进入 holding。place 命令先 transport(objectHeld + atTarget),再 place(released + !objectHeld + atTarget)。保持抓持期间每 1.2 秒内须有新鲜 objectHeld 反馈。抓空仅重试一次。每阶段最多 2.5 秒。所有远端反馈还需有效 session/commandId、递增 sequence、客户端时间差 ≤500ms;双方需校时。真实外部接入不能把框存在当作抓持证据。
核心帧间隔最多 500ms,源变化/尺寸改变/目标丢失/歧义/滑落/矛盾反馈/超时均停止活动动作。停止后旧 session 的反馈无效。页面隐藏会主动停止。浏览器不是实时控制系统;仿真器/实际设备必须有独立超时停止与硬件急停。不要将此原型直接接到真实电机。
### 跟踪
12×12 RGB 模板采样,±22px 的局部候选搜索,固定模板防漂移,无检测模型/YOLO/VLM。置信度是绝对颜色差启发式,不是校准概率。相似候选间差距过低则拒绝。缓存最多 30 帧 / 3 秒,按原帧初始化并依次追赶;超时或追赶失败转入有界全局重捕获。显式 retainReference(frameId) 最多保留4张原帧、60秒;UI 按下框选时自动保留。selectTarget 也可带 reference:{width,height,data} 原始参考帧。没有参考则返回 needs_reference 而不抛出硬错误;有参考时仅在当前新鲜帧找到唯一强匹配才恢复。reacquireTarget() 可手动重试,每秒最多一次、最多约6000粗候选加局部精查。重捕获不自动重启动作。限制:不能可靠处理大幅缩放/旋转、遮挡、同色同形目标或高速运动。UI 显示实际采样 FPS 与跟踪耗时,默认约 10Hz 本地处理,不保证任何设备帧率。
## 远端视频与控制
两端打开同一部署 origin。控制端「新建会话」生成 256bit 随机能力码(30分钟有效);手动交给可信发送端,在两端点击连接。会话码仅保存在页面内存/字段,刷新即消失,不进 URL、不持久化。URL 中仅传 SHA-256 房间标识;hello 消息携带能力码与角色 controller/simulator。知道码的人可加入该房间,不能把它当永久账号权限。
公开的是静态演示页面,不是公开视频房间。无视频存储、录像或账号认证。每房间一个控制端和一个发送端(最多 4 条未认证连接),同源浏览器 Origin 校验,非浏览器适配器需持有能力码。此为原型,并未提供全局 DDOS 防护或总费用硬上限。
### 首选 WebRTC
WebSocket 只中继 offer/answer/ICE 与控制反馈,视频浏览器间传输。MediaStream 标准视频轨道,编解码由浏览器协商。无 STUN/TURN 服务器、无 Worker 媒体转发的虚假假设;跨 NAT 直连可能失败。6秒未连接或连接失败后双方切换 WS JPEG。远端采样与本地跟踪独立。现场弱网与跨手机 WebRTC 尚需实机测试。
### WS JPEG 回退(应用自定义封装,不声称标准视频容器)
每条 WebSocket binary 消息 = 24字节 big-endian 头 + 一个完整 JPEG:
- 0: uint32 magic 0x43423038(CB08)
- 4: uint32 单调 frameId
- 8: float64 captureTime(Unix 毫秒)
- 16: uint16 width,18: uint16 height(24..640 / 24..480)
- 20: uint32 JPEG 长度;24 起 JPEG 字节
最大整包 512KiB,不用 base64。发送端同一时刻最多一个待发送/待接收确认帧;controller 在解码后发 frameAck。中继对每个 controller 最多一个未确认帧,积压时丢弃新到旧帧,不排长队;下一空槽取随后新帧。慢消费者超1.5秒关闭。每连接40消息/秒;文本最多8KiB。JPEG 入站时钟差最多2秒,浏览器丢弃超过1.5秒的帧。
JSON 消息:hello{role,token}、signal{data:{kind:'offer'|'answer'|'ice'|'fallback',sdp/candidate}}、action{data:动作事件}、feedback{data:传感器证据}、frameAck{frameId}、ping/pong、disconnected。远端 feedback.timestamp 使用 Date.now(),前端经新鲜度校验转为本地 performance.now()。源码 VideoBridge 是完整适配器示例;simulator.js 展示视频与动作反馈,不需要真实仿真器即可检查链路。
## 验证边界
Node 单元测试与 Worker/DO mock 验证协议和状态转换;不是 Cloudflare runtime 仿真。真实相机权限、手机 Safari、外部物理仿真器和公网 WebRTC NAT 穿透分别需要实机验证。合成演示成功不能证明真实机器人可以抓取。