关于 OBSBOT Tiny 2 Camera Control
这是一款跨平台 MCP 服务,可通过 USB 控制 OBSBOT Tiny 2,也可通过网络 API 控制 OBSBOT Tail 2。它向 MCP 客户端提供云台、图像设置、跟踪、拍摄和录制控制。
主要功能
- 01控制云台平移、俯仰和滚转
- 02调整变焦、对焦、曝光和白平衡
- 03管理 AI 跟踪、HDR 和视场
- 04拍摄快照、预览和录制视频
- 05发现并指定多台摄像头
- 06可选诊断状态与底层控制
适用场景
- 01在通话或直播中调整 Tiny 2 画面
- 02根据摄像头快照对准目标
- 03将可见区域框入摄像头画面
- 04排查问题时检查摄像头状态
MCP 相关
通过 stdio 运行 MCP 服务,并向 MCP 客户端提供摄像头控制工具。启用 --debug 后会增加诊断工具;还可提供控制网络中 OBSBOT Tail 2 的工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
80收录的工具列表 · 更新于 2 周前
此工具无需参数。
详细介绍
obsbot-mcp
一个跨平台的 Model Context Protocol 服务,通过标准 UVC/USB 接口控制 OBSBOT Tiny 2 摄像头——平移/倾斐/滚转云台、变焦、AI 主体追踪、对焦/曝光/白平衡/图像控制、HDR 和视场,以及拍摄快照、预览和录像——无需任何厂商 SDK。它还可通过 HTTP/WS API 控制 OBSBOT Tail 2 网络摄像头(见下文 OBSBOT Tail 2)。
安装
npm install obsbot-mcp
MCP 客户端配置
添加一个指向已安装二进制文件的 stdio 服务条目(或直接指向 dist/index.js):
{
"mcpServers": {
"obsbot": {
"command": "obsbot-mcp"
}
}
}
如果是从本地检出版本运行,而非通过 npm 安装,请将 command/args 指向 node 和构建后的入口点:
{
"mcpServers": {
"obsbot": {
"command": "node",
"args": ["path/to/obsbot-mcp/dist/index.js"]
}
}
}
调试/诊断工具
默认情况下,该服务仅公布常规控制功能。传入 --debug 可额外启用诊断功能——obsbot_debug_probe 工具(原始 XU 字节获取/设置/查询)以及 obsbot_status 中的 raw 60 字节状态块:
{
"mcpServers": {
"obsbot": {
"command": "node",
"args": ["path/to/obsbot-mcp/dist/index.js", "--debug"]
}
}
}
使用已安装的二进制文件时,设置 "command": "obsbot-mcp" 和 "args": ["--debug"]。
工具
Windows 和 macOS 上有 35 个工具,Linux 上有 34 个(该平台不提供 obsbot_gimbal_move_speed——见限制)。--debug 会额外添加 obsbot_debug_probe,共多出一个工具。网络上的每台 Tail 2 摄像头都会增加 32 个 obsbot_tail2_* 工具,详见下文的 OBSBOT Tail 2(所有平台均支持——这些工具完全由 TypeScript 实现)。
以下名称均为 v0.4.0 中的当前名称——本次发布重命名了所有工具,且没有向后兼容的别名;如果你正在更新调用方,请参阅 CHANGELOG.md 查看完整的新旧名称对应关系。
camera 选择器
每个用于指定摄像头的工具都接受可选的 camera 参数:目标摄像头的序列号。连接单台摄像头时省略该参数不会改变任何行为——这与服务在 v0.4.0 之前的单摄像头行为完全一致。连接多台摄像头时,若调用中省略 camera,则会报错并列出所有已连接摄像头的序列号,让你始终清楚下一步应传入什么值。
例外(始终不接受 camera 参数):obsbot_devices(枚举所有设备)、obsbot_capture_stop / obsbot_capture_list(通过 sessionId 而非设备定位),以及 obsbot_debug_probe(对当前诊断传输进行操作)。还有两个工具仅部分支持该参数——见下文的拍摄。
多摄像头支持是 v0.4.0 新增的功能。该功能已通过针对模拟对象的单元测试套件进行测试;同时运行两台实体 Tiny 2 尚未经过硬件验证(见已知限制)。
obsbot_devices 可用于查找要传给 camera 的序列号:它会报告每台已连接摄像头的 serial(若可获取——读取该值需要短暂打开摄像头)、name 和 status(available | bound | busy)。如果摄像头已被其他进程占用,则会显示为 busy,且不返回序列号,因为无法打开摄像头读取该值。
设备与电源
| 工具 | 参数 | 描述 |
|---|---|---|
obsbot_devices | — | 列出已连接的 OBSBOT 摄像头,并显示每台摄像头的序列号(如可获取)、名称和状态(available/bound/busy)。busy 表示摄像头正由另一个进程占用。 |
obsbot_wake | camera? | 唤醒摄像头/云台(发送 "run")。**会移动摄像头:**将收起的云台恢复至水平位置(俯仰角约为 0)。大多数控制命令也会隐式唤醒摄像头。 |
obsbot_sleep | camera? | 让摄像头/云台进入睡眠状态(发送 "sleep")。**会移动摄像头:**将云台收起,使镜头朝下,俯仰角约为 84;因此 obsbot_gimbal_position 读数约为 84,而不是你离开时的姿态。 |
obsbot_status | camera? | 读取实时状态块:{ awake, hdr, faceAe, aiMode, trackSpeed, fovMode, zoomPercent, focusMode, focusPosition }(faceAe = 对检测到的人脸进行自动曝光测光;fovMode = wide|medium|narrow|custom|unknown,其中 custom 表示连续变焦覆盖了离散模式;zoomPercent = 变焦位置,范围为 0-100;focusMode = auto|manual|unknown)。focusPosition 仅在手动模式下出现,其范围为 0-100,与 obsbot_focus_manual 使用的范围相同——在自动对焦模式下,摄像头会返回上次写入的值,而不是报告电机位置,因此该数值会过时,却看起来像实时对焦距离。对焦是标准 UVC 控件,不属于状态块,因此需要额外读取一次;无法响应的设备会报告 focusMode: "unknown",而不会导致整个调用失败。启用 --debug 时,还会以十六进制形式返回原始 60 字节状态块。 |
云台(PTZ)
| 工具 | 参数 | 描述 |
|---|---|---|
obsbot_gimbal_move | yaw、pitch、roll(度,roll 默认为 0)、camera? | 将云台移动到绝对角度。正向 yaw 会向摄像头左侧水平转动,正向 pitch 会向下倾斜。Yaw 限定在 [-150, 150],pitch 限定在 [-90, 90]。绝对角度为 1:1,已通过硬件验证。 |
obsbot_gimbal_move_speed | yaw、pitch、roll(度/秒,限定在 ±150,roll 默认为 0)、autoStopMs(默认为 800)、camera? | 以指定速度驱动云台,然后在 autoStopMs 后自动停止,避免云台失控。Yaw/pitch 正负方向与 gimbal_move 相同。返回实际使用的速度。超过限值后,固件会直接忽略命令,而非将速度限制到上限——速度达到 180 度/秒及以上时,云台的转动角度恰好为 0°——因此请求会被限制在经过硬件验证的范围内。Linux 上不可用——参见限制。 |
obsbot_gimbal_recenter | camera? | 将云台重新居中——驱动云台转至 yaw 0 / pitch 0。命令发送后立即返回;若要确认云台是否到位,请轮询 obsbot_gimbal_position。 |
obsbot_gimbal_position | camera? | 通过标准 UVC Pan/Tilt 读取云台当前的绝对 { yaw, pitch }(度)。转动过程中和转动完成后均可读取。Linux 上返回的是最近一次命令设定的值,而非转动过程中的实时读数——参见限制。 |
obsbot_aim_at_pixel | x、y、frameWidth、frameHeight、source(默认为 "device")、camera? | 将摄像头对准刚刚捕获的帧中的某个像素。读取摄像头自行报告的放大倍率状态——无论是离散 FOV 模式还是连续变焦模式——因此无需提供 FOV 或变焦参数,适用于任何变焦倍率。以下情况会拒绝执行:AI 跟踪处于激活状态;无法解码 FOV 模式;变焦读数损坏,导致计算出的放大倍率不合理;摄像头必须先唤醒(唤醒会移动云台,使测量所依据的帧失效);或者变焦仍在渐变过程中(捕获帧时的放大倍率已不再是摄像头当前的放大倍率,因此请等待变焦完成后重新拍摄快照)。source 用于声明帧的来源(默认为 device)——无法仅凭像素推断来源。virtual/ndi 帧可以接受,不会被拒绝,但只有在该画面是摄像头未经修改的直通信号时才能正确瞄准;合成器进行的缩放或加黑边在画面中无法察觉,因此会导致结果悄然出错。为此,声明非 device 来源时会返回一条说明该假设的 note。该工具会读取实时姿态来计算瞄准位置,因此在 Linux 上也会受到与 obsbot_gimbal_position 相同的影响——参见限制。如果目标超出云台范围,则返回 clamped:true,但摄像头仍会移动到最近的可达姿态。如果像素位于当前姿态的垂直方向之外,则拒绝执行(ok:false),而不会移动,因为唯一能到达该位置的旋转方式会使摄像头转向房间另一侧;请先朝该像素倾斜,再重新瞄准。 |
obsbot_zoom_to_fit | x、y、width、height、frameWidth、frameHeight、margin(默认为 0.1)、source(默认为 "device")、camera? | 为刚刚捕获的帧中的某个区域取景:将云台对准该区域的中心,并变焦至区域填满画面。拒绝条件与 obsbot_aim_at_pixel 相同(AI 跟踪、无法解码 FOV/变焦、摄像头刚被唤醒、变焦仍在渐变、目标位于垂直方向之外、帧宽高比不是 16:9),并要求同样声明 source;此外,如果区域不在帧内(包括边缘),或者尺寸不是正数,也会拒绝执行。margin 会按指定比例缩小变焦倍率,避免区域紧贴画面边缘;由区域两条轴中更紧的一条决定变焦倍率,从而确保整个区域都可见,不会有一侧被裁切。先移动云台,再变焦——变焦会保持画面中心,但不会保持目标位置,因此先变焦可能使区域移出画面。变焦是渐变而非瞬间完成,因此该工具最多轮询 3s;如果变焦未能及时完成,则返回 settled:false(并非错误)——请先检查该值,再决定是否信任后续快照。 |
对准你看到的目标
obsbot_capture_snapshot 会将画面作为图像返回,并附带 width/height,这样模型就能在图片中定位目标,然后让摄像头对准它:
obsbot_capture_snapshot— 查看画面obsbot_aim_at_pixel— 传入目标像素坐标和该画面的尺寸- 再次调用
obsbot_capture_snapshot— 确认是否已对准,必要时重复操作
传入像素坐标所对应的同一张快照的 frameWidth/frameHeight。将一张画面中的像素坐标与另一张画面的尺寸混用,会导致对准错误的位置,而且无法检测出来。
快照的 source 必须为 "device"。 obsbot_capture_snapshot 也可以从 source: "virtual" 或 "ndi" 读取画面,但这些画面来自 OBSBOT Center 自身的输出,而非摄像头的原始视频流。这些画面由 OBSBOT Center 进行取景和裁剪,而非由摄像头光学系统完成,因此本工具依赖的实测视场常数并不适用于这些画面——根据虚拟画面或 NDI 画面进行对准会落在错误位置,且无法检测出来。此处只能使用 device 来源快照中的像素坐标和尺寸。
该工具会自行读取摄像头的放大倍率,无论是离散的 FOV 模式还是连续变焦(在硬件上测得,精度优于 0.05%,计算公式为 m = 3*ratio-2),因此无需传入 FOV 或变焦参数,也就不会因参数错误而导致对准失误,并且适用于任何变焦级别。如果 AI 跟踪已开启(跟踪会驱动云台,与对准操作相冲突)、无法解码 FOV 模式、变焦读数损坏导致计算出的放大倍率不合理,或摄像头需要从休眠状态唤醒,工具会拒绝执行,而不会猜测(唤醒会移动云台,因此测量所依据的画面将不再与摄像头的指向相符——请重新拍摄快照后重试)。
确定取景范围
obsbot_zoom_to_fit 将同样的思路从点扩展到区域:它不仅会以某个像素为中心,还会进行变焦,让该区域填满画面。
obsbot_capture_snapshot— 查看画面- 为需要填满画面的对象(人脸、白板等)选取一个边界框
obsbot_zoom_to_fit— 传入边界框(x、y、width、height)以及该画面的尺寸- 再次调用
obsbot_capture_snapshot— 确认取景效果,必要时重复操作
它与 obsbot_aim_at_pixel 一样,在启用 AI 跟踪、FOV/变焦值无法解码、相机已唤醒、变焦仍在调整或画面不是 16:9 时会拒绝操作。此外,它还有一项额外限制:区域必须位于画面内(包括边缘,因此已覆盖整个画面的区域也有效),且宽度和高度必须为正数。否则,该工具会拒绝调用,而不会猜测负宽度或超出画面的边界框原本表示什么。
margin(默认值为 0.1,即 10%)会按该比例降低请求的变焦倍率,使区域不会刚好贴边填满画面,从而为其周围留出一定余量,以应对轻微的瞄准或变焦误差。区域的两个轴通常需要不同的变焦倍率才能填满画面;该工具始终选择所需倍率中较小的一个,因为选择较大的倍率会使一个轴填满画面,同时裁掉另一个轴。最终倍率会限制在相机的 [1x, 4x] 范围内(通过 clamped 报告);即使某个区域需要的变焦倍率超出相机能力,也会采用最接近的可用取景效果,而不会直接拒绝操作。
云台会先移动,然后才会下达变焦指令。变焦会重新调整当前画面中的取景范围,但不会在变焦过程中让特定像素始终保持在准星下方:如果先变焦,区域中心可能会完全移出画面,导致后续移动瞄准的像素与调用方测量时所指的像素不再相同。
变焦并非瞬时完成:在此硬件上,变焦会逐渐接近指令指定的数值,而不是立即跳到该数值。因此,在下达指令后立即读取状态,可能会发现变焦仍在调整中(观察结果:指令要求的倍率为 1.5,读取时尚未完成,之后才稳定下来)。obsbot_zoom_to_fit 最多会轮询 3 秒,等待变焦完成;若超时仍未完成,会返回 settled:false,这不代表错误。变焦仍在移动时拍摄的画面,其倍率无法确定,因此在信任后续快照之前,请先检查 settled;返回 false 仅表示相机移动速度低于预期,并不表示操作失败。
云台预设
设备上有三个预设槽位(1–3)。槽位只能创建一次:obsbot_preset_save 要求槽位为空(要重复使用槽位,必须先删除);其他预设工具则要求槽位已被占用。每个工具在写入后都会重新读取槽位列表;如果设备未能完成更改,则会返回结构化的 { ok:false } 失败结果。
| 工具 | 参数 | 描述 |
|---|---|---|
obsbot_preset_list | camera? | 读取三个预设槽位:占用/空闲状态、名称和以度为单位的姿态。 |
obsbot_preset_save | slot (1|2|3), camera? | 将云台当前的实时姿态保存到一个空闲槽位。 |
obsbot_preset_recall | slot (1|2|3), camera? | 调用一个已占用的槽位,驱动云台移动至保存的姿态。 |
obsbot_preset_update | slot (1|2|3), camera? | 用云台当前的实时姿态覆盖一个已占用的槽位。 |
obsbot_preset_rename | slot (1|2|3), name, camera? | 重命名一个已占用的槽位(超过 40 字节的名称会被截断)。 |
obsbot_preset_delete | slot (1|2|3), camera? | 删除一个已占用的槽位,以便用于 obsbot_preset_save。 |
Zoom
有两个工具,而不是一个——它们使用不同的传输方式(标准 UVC 与厂商命令帧),
并且在相同的命令 ratio 下产生不同的实际变焦效果,因此合并它们会悄然改变
ratio 的含义。请根据所需行为选择。
| 工具 | 参数 | 描述 |
|---|---|---|
obsbot_zoom_uvc | ratio(1.0–2.0),camera? | 标准 UVC 变焦:设置绝对变焦比例,并将其限制在 [1.0, 2.0]。会精确到达请求的目标值。等待变焦完成后返回 settled——变焦过程并非瞬时完成(从 1.0 全程变到 2.0 约需 2.4s),且在变焦过程中,obsbot_aim_at_pixel / obsbot_zoom_to_fit 会拒绝执行,因此提前返回只会把故障推迟到后续步骤。settled:false 表示在超时时间内尚未到达目标;命令仍已发送。 |
obsbot_zoom_vendor | ratio(1.0–2.0),speed(默认 0),camera? | 厂商变焦路径,支持调节速度:以选定速度变焦至指定比例(0 = 设备默认值,1–10 从慢到快,255 = 最大速度)。其比例刻度与 obsbot_zoom_uvc 的不同,且不一定会精确到达请求的目标值——请参阅已知限制。 |
AI 跟踪
| 工具 | 参数 | 描述 |
|---|---|---|
obsbot_ai_track | enabled(bool),mode(默认 "normal"),camera? | 启用/禁用 AI 跟踪并选择模式:人物取景模式(normal | upper-body | close-up | headless | lower-body)或场景模式(group | whiteboard | desk | hand)。轮询状态并返回 { verified, matched }(matched:false = 尚未跟踪到主体)。 |
obsbot_ai_track_speed | speed:"standard" | "sport",camera? | 设置跟踪速度预设(Center 的 Standard/Sport):standard(跟随速度较慢)或 sport(响应更灵敏)。 |
obsbot_focus_face | enabled(bool),camera? | 启用或禁用人脸优先自动对焦。 |
图像与镜头
从 v0.4.0 开始,对焦、白平衡和曝光各自拆分为专用的 _auto 与 _manual 工具
(此前是一个带模式参数的工具)——自动和手动模式需要不同的参数,因此拆分后每个
工具的架构都能准确声明所需参数。
| 工具 | 参数 | 描述 |
|---|---|---|
obsbot_image_fov | fov:"wide" | "medium" | "narrow",camera? | 设置视野:宽(86°)、中(78°)、窄(65°)。 |
obsbot_image_hdr | enabled(bool),camera? | 开启或关闭 HDR/WDR 成像。 |
obsbot_focus_auto | camera? | 启用连续自动对焦。 |
obsbot_focus_manual | position(0–100,默认 50),camera? | 将对焦马达设置到 position(从近到远)。 |
obsbot_image_exposure_auto | priority("global" | "face",可选),camera? | 启用自动曝光;可选的 priority 用于选择全局测光或人脸测光。 |
obsbot_image_exposure_manual | level(0–100,默认 50),camera? | 设置曝光 level(0 最暗 → 100 最亮)。 |
obsbot_image_wb_auto | camera? | 启用自动白平衡。 |
obsbot_image_wb_manual | temperature(开尔文,默认 5000),camera? | 设置色温(限制在设备范围内)。 |
obsbot_image_adjust | control,level(0–100),camera? | 调整 brightness | contrast | hue | saturation | sharpness | gain | backlight-compensation;level 会映射到设备范围。Tiny 2 未实现 gain 和 backlight-compensation(设备将它们报告为零长度控件),因此会拒绝这些参数并报错;其他五项均可用。 |
采集
obsbot_capture_record 和 obsbot_capture_preview 不接受 camera。 它们通过 ffmpeg/ffplay 按 source(device/virtual/ndi)选择设备,而非按序列号选择——目前尚无序列号到 ffmpeg 设备的映射。obsbot_capture_snapshot 仅在 source:"device" 时遵循 camera;对于 source:"virtual"/"ndi",像素来源仍按设备名称解析,与 camera 无关。
| 工具 | 参数 | 描述 |
|---|---|---|
obsbot_capture_snapshot | resolution(256–1920,默认 640)、quality(1–100,默认 80)、settleMs(0–15000,默认 600)、source(默认 "device")、camera?(仅限 source:"device") | 抓取一帧静态图像并将其作为图像返回(用于检查取景、照明和曝光)。resolution 是像素中的最长边——数值越大,消耗的令牌也按比例越多。source:device | virtual | ndi。还会返回 sourceFormat——采集图通过协商确定的格式,例如 MJPG [email protected]——因为帧率会决定此相机的视野范围(见限制);仅限 Windows,未提供时表示未知。连接较慢的来源(NDI)可能需要更大的 settleMs。 |
obsbot_capture_record | durationSec(可选)、audio(默认 true)、outputPath(可选)、source(默认 "device") | 开始录制为 MP4。未设时长的录制会在 60 分钟后自动停止;音频使用 OBSBOT 麦克风;所有平台的默认路径均为 ~/Videos/OBSBOT,包括 macOS(该路径并非通常使用的 ~/Movies)。返回 sessionId。**需要 ffmpeg。**¹ 无 camera。 |
obsbot_capture_preview | source(默认 "device") | 打开实时预览窗口。返回 sessionId。**需要 ffplay。**¹ 无 camera。为确保画面流畅,device 固定为 1080p60 mjpeg——但这会缩小视野范围(见限制)。virtual/ndi 则自行协商,因为它们都不提供 mjpeg,强行固定该格式会导致设备无法打开。 |
obsbot_capture_stop | sessionId | 停止录制或预览会话(录制会正常完成)。无 camera。 |
obsbot_capture_list | — | 列出正在进行的录制/预览会话。无 camera。 |
诊断(仅限 --debug)
| 工具 | 参数 | 描述 |
|---|---|---|
obsbot_debug_probe | mode:"get" | "set" | "query",以及 selector、length、hex、opcode、payloadHex | 仅用于 RE/诊断——原始 XU 字节读写和带帧表格查询。仅在 --debug 下公布。无 camera。 |
¹ record/preview 会调用 ffmpeg/ffplay(安装方式:Windows 上运行 winget install Gyan.FFmpeg
,macOS 上运行 brew install ffmpeg,Linux 上运行 apt install ffmpeg)。snapshot 不需要
ffmpeg——它通过原生辅助程序抓取帧。
OBSBOT Tail 2(网络摄像机)
Tail 2 与众不同:它是一款网络 PTZ 摄像机(输出支持 NDI/RTSP/SRT/RTMP,配备以太网和 WiFi,
USB-C 端口可用于 MTP 素材传输,也可作为 UVC 网络摄像头)。以下工具使用其
网络控制平面——HTTP REST API 和 WebSocket 状态推送,相关文档见基于设备逆向工程编写的
TAIL2-PROTOCOL.md。因此,整个模块都是纯 TypeScript,不含任何平台专属代码:没有原生辅助程序,无需构建辅助程序,
在 Windows/Linux/macOS 上行为完全一致。
在 UVC 模式下,相机也会通过 USB 响应标准 UVC 控件(平移、倾斜、缩放、平移/倾斜速度、 对焦、曝光、白平衡),其厂商扩展单元则提供跟踪开关、人体跟踪模式、跟踪速度和自动缩放功能。此服务尚无 Tail 2 USB 传输支持,因此这些功能均未作为工具公开;预设、竖屏旋转和横滚微调仅支持网络控制。有关测量结果,请参阅 TAIL2-PROTOCOL.md §11。
入门指南:
- 将 Tail 2 接入网络(以太网默认使用 DHCP)。
- 调用一次
obsbot_tail2_scan— 它会监听约 5 秒,接收相机自身的 mDNS 通告(每隔几秒多播其 MAC、名称和 IP,这也是 OBSBOT Center 用来发现相机的通道),仅在多播受限的网络中才会回退到 HTTP 子网扫描。也可以在服务的环境中设置OBSBOT_TAIL2_HOSTS(以逗号分隔的地址),或者直接为任意 Tail 2 工具传入一个包含相机 IP 的camera参数。
这些工具的 camera 选择器可以是相机的 MAC(其稳定标识)、device_name 或主机地址,且不区分大小写。若只注册了一个 Tail 2 而未提供该参数,则会解析为这台相机。
| 工具 | 参数 | 描述 |
|---|---|---|
obsbot_tail2_devices | — | 列出已注册的 Tail 2 摄像头(mac、名称、主机名)。注册不代表设备在线。 |
obsbot_tail2_scan | — | 搜索 Tail 2 摄像头:监听 mDNS 约 5 秒(摄像头自身的广播),并在失败时回退到 HTTP 子网扫描。将找到的设备注册。 |
obsbot_tail2_status | camera? | 获取一次 WebSocket 状态推送:完整实时信息块,包括电源、录制、竖屏、人类跟踪模式及跟踪设置、缩放比例、横滚偏移、对焦模式、NDI/RTSP/SRT/RTMP 标志、SD 卡、带姿态的预设,以及各子系统健康状态。没有实时偏航/俯仰数据——Tail 2 云台采用开环控制。 |
obsbot_tail2_info | camera? | 一次调用获取身份信息和静态配置:device_info、range(缩放 1.0–12.0、对焦 1–100、白平衡 2000–10000 K)、networkconfig(NDI/流设置)。 |
obsbot_tail2_zoom | ratio(1.0–12.0)、speed(1–10,默认值 5)、camera? | 按摄像头自身的比例刻度进行绝对缩放。固件要求提供 speed。返回 settled(经读回验证)——见下文。除非解锁混合变焦,否则缩放会静默限制在 5.0(光学变焦上限)——参见 obsbot_tail2_hybrid_zoom。 |
obsbot_tail2_hybrid_zoom | enabled、camera? | 解锁(或重新锁定)5–12 倍数字变焦范围——这是 OBSBOT Center 控制的开关,REST API 中没有此功能(缩放超过 5.0 的请求虽会收到确认,但在运行此工具前仍会被限制)。直接使用 Center 的私有 UDP-9999 协议,两个校验和均已解码;通过实时状态快照(zoom_infos.digital_enable)读回验证,Center 关闭时也能运行。已于 2026-09-30 在硬件上验证两个方向。 |
obsbot_tail2_recenter | camera? | 将云台重新居中(偏航/俯仰/横滚归零)。采用开环控制:收到确认后即返回。可能会将 AI 跟踪切换为 none;可通过 obsbot_tail2_ai_track 重新启用。 |
obsbot_tail2_gimbal_position | camera? | 通过保存临时预设 → 读取 → 删除(约 2 秒),获取实时云台姿态(偏航/俯仰/横滚,单位为度)和缩放比例。需要一个空预设槽(探测用槽会自动清理)。 |
obsbot_tail2_gimbal_speed | yaw? pitch? roll?(速度 ±150)、durationMs?(100–5000,默认值 500)、camera? | 以摇杆原语控制云台短暂移动,并自动停止。实测:命令值 20 ≈ 7.9°/秒;正向偏航命令会使记录的偏航角减小。请先禁用 AI 跟踪。 |
obsbot_tail2_gimbal_move | yaw? pitch?(±178°)、camera? | 通过闭环控制绝对移动(短暂移动 → 读取姿态 → 校正,最多 5 轮,容差 ±1.5°)。按设计速度较慢(小幅移动约 1 秒,大幅移动耗时更长)。AI 跟踪处于活动状态时会拒绝执行。已于 2026-09-30 在硬件上验证:4° 移动在一轮内完成。 |
obsbot_tail2_gimbal_invert | enable?、camera? | 读取(不带参数调用)或设置(经验证)控制方向反转。 |
obsbot_tail2_record | enable?、camera? | 读取或控制录制开关。需要存储空间——请检查 obsbot_tail2_status 的 sdcard 字段。 |
obsbot_tail2_capture_photo | camera? | 拍摄一张静态照片(存储到设备中)。 |
obsbot_tail2_focus | mode?(afc/afs/mf)、position?(0–100)、camera? | 读取或设置对焦。仅当模式为 mf 时才能设置位置(受模式限制;否则工具会拒绝执行)。 |
obsbot_tail2_exposure | mode?、face?、evbias?、iso?、shutter?、camera? | 读取(取决于模式)或设置曝光:自动(面部优先自动曝光 + EV 偏移)或手动(ISO 100–6400、快门 1/N)。注意:固件会拒绝 JSON 整数类型的 evbias——客户端始终发送 0.0 形式的浮点数。 |
obsbot_tail2_image_adjust | control?、value?(0–100)、styleMode?、camera? | 读取或设置图像风格(亮度/对比度/色调/饱和度/锐度)。仅当 styleMode 为 manual 时才能写入控制项——工具会先应用给定的 styleMode,否则会拒绝执行。 |
obsbot_tail2_hdr | enabled?、camera? | 读取/设置 HDR。 |
obsbot_tail2_wb | mode?、temperature?(2000–10000 K)、camera? | 读取/设置白平衡(6 种模式,手动模式下可设置开尔文值)。 |
obsbot_tail2_stream | output?(ndi/rtsp/srt/off)、camera? | 读取/设置唯一启用的网络输出。以编程方式为 obsbot_tail2_snapshot 启用 SRT——无需 Center。 |
obsbot_tail2_only_me | enabled?、camera? | 读取/设置 OnlyMe 人体跟踪(只跟踪一个人,而不是所有人)。 |
obsbot_tail2_audio | volume?、mute?、camera? | 读取/设置音频输入。 |
obsbot_tail2_zoom_type | type?(normal/shot/halfBody/fullBody/P7/P9/P16/P24)、camera? | 读取/设置自动缩放取景模式(Center 的跟踪滑块)。写入受限:必须已启用人体跟踪。 |
obsbot_tail2_preset_speed | speed?(1–5)、camera? | 读取/设置预设切换速度。 |
obsbot_tail2_usb_mode | mode?(mtp/uvc)、camera? | 读取/设置 USB-C 功能模式。 |
obsbot_tail2_antiflicker | mode?(off/50hz/60hz)、camera? | 读取/设置防闪烁。 |
obsbot_tail2_af_track | mode?(global/face/front)、camera? | 读取/设置自动对焦跟踪模式。 |
obsbot_tail2_iso_range | min?、max?(100–6400)、camera? | 读取/设置自动 ISO 范围(双滑块;省略的边界值保持不变)。 |
obsbot_tail2_gesture | lockedTarget?、recording?、zoom?、zoomFactor?、camera? | 读取(不带参数调用)或设置手势控制开关和缩放因子。 |
obsbot_tail2_stream_config | encoder?、resolution?、bitrate?、camera? | 读取(不带参数调用,包含 RTSP URL)或设置流编码器配置。只有在输出关闭时才能设置分辨率。 |
obsbot_tail2_export_log | path、camera? | 将完整诊断包(Export Log 压缩包:ust.json、status.json、工厂记录、内核日志)下载到 path。约 10–20 秒。 |
obsbot_tail2_live_status | camera? | 获取精简的最新运行时快照:实时云台姿态(欧拉角 + 关节)、缩放内部状态(包括 hybridDigitalEnable)、实际运行时曝光、温度、启动阶段和配件。 |
obsbot_tail2_zone_tracking | enabled、camera? | 切换区域跟踪(UDP 9999 键 03)。没有读回功能——效果会体现在跟踪行为中。 |
obsbot_tail2_auto_zoom_speed | speed(1–10)、camera? | 设置 AI 自动缩放取景速度(UDP 键 0x17;与手动缩放速度不同)。无法读回。 |
obsbot_tail2_track_custom | enabled?、pan?、tilt?(1–10)、panAuto?、tiltAuto?、camera? | 读取(不带参数调用)或配置自定义跟踪速度:各轴速度、Auto 按钮(通过 tracking_settings 读回验证)。轴锁定状态仅供读取——目前没有已知的写入方式。 |
obsbot_tail2_track_target | x、y(0.01–0.99)、camera? | 点按跟踪:根据归一化画面坐标(快照像素坐标 ÷ 画面尺寸),让 AI 跟踪目标。未公开的端点,已通过硬件测量。 |
obsbot_tail2_focus_point | x?、y?(0.01–0.99)、camera? | 点按对焦:将对焦窗口移至归一化画面坐标并启动点对焦(仅限 afc/afs)。不带参数调用可读取窗口位置。 |
obsbot_tail2_portrait | enable、camera? | 电动旋转机身 90°以进行竖屏取景——Tiny 2 没有同等功能。已通过方向反馈验证;若返回 settled:false,请重试(实测发现,电机运动期间写入可能被静默丢弃)。 |
obsbot_tail2_roll_bias | angle(±90)、camera? | 以度为单位设置横滚微调(地平线校正/有意倾斜)。 |
obsbot_tail2_ai_track | enabled、mode(默认值 "humanTrackingSingleMode")、camera? | 启用/禁用 AI 跟踪。模式采用摄像头自身的枚举值:人体(单人/群组)、动物(普通/特写)、物体跟踪(objectTracking/objectTrackingNormal/objectTrackingCloseUp)。跟踪启用时,云台由跟踪控制。 |
obsbot_tail2_track_speed | speed:"superLazy" | "lazy" | "slow" | "fast" | "crazy" | "customized"、camera? | 跟踪跟随速度——Tail 2 自身的六档枚举(不是 Tiny 2 的标准/运动两档)。 |
obsbot_tail2_preset_list | camera? | 列出三个预设槽:已占用/空闲状态、解码后的名称、以度为单位的姿态及缩放比例。 |
obsbot_tail2_preset_save | slot(1–3)、name?(默认值 P1/P2/P3)、camera? | 将当前实时姿态保存到槽位——请先调整镜头,再保存。会覆盖已占用的槽位(与 Tiny 2 的只能创建一次不同),且此 API 完全不支持按数值写入姿态。 |
obsbot_tail2_preset_recall | slot、camera? | 驱动云台和缩放至已保存的姿态。空槽位会被拒绝。通过缩放读回验证是否到位(云台轴为开环控制——Tail 2 不报告实时姿态)。请先禁用 AI 跟踪,否则它会干扰移动。 |
obsbot_tail2_preset_delete | slot、camera? | 释放一个槽位。 |
obsbot_tail2_preset_rename | slot、name、camera? | 重命名槽位(自动处理 base64)。 |
obsbot_tail2_snapshot | resolution(256–1920,默认值 640)、quality(1–100,默认值 80)、camera? | 抓取一帧静态画面并以图像形式返回。从摄像头的 SRT 输出获取画面(ffmpeg SRT caller,端口 5000)——需要先在 OBSBOT Center 中启用 SRT 监听器模式(启用后会禁用 NDI,摄像头重启后也会关闭;Center 只有在输出关闭时才允许更改流设置,因此失败通常意味着 SRT 已关闭——重新启用后重试)。已于 2026-09-26 在硬件上验证。 |
每次写入后都会回读验证(结果中的 settled):Tail 2 会确认指令,即使执行器正处于运动过程中,也可能丢弃这些指令——{"code":200} 表示已确认,而非已应用(测量日期为 2026-09-26;参见 TAIL2-PROTOCOL.md §8)。settled:false 表示在回读结果一致之前,重试次数已用尽;指令仍已发送——请重试。 |
已知的 Tail 2 限制(详情见 TAIL2-PROTOCOL.md §9):尚未探测通过 REST 写入图像控制的情况;快照功能依赖于在 OBSBOT Center 中启用摄像头的 SRT 输出(与 NDI 互斥,重启后会清除——如果 SRT 已关闭,工具会对此作出说明;在此固件版本上,RTSP 输出即使启用了开关也始终无法提供数据)。摄像头的控制 API 也未经身份验证——局域网中的任何人都能控制摄像头,包括将其关机。
支持的平台
-
Windows x64 — 当前支持。原生辅助程序由
native/windows/中的源代码构建(CMake + MSVC);已发布的 npm 包附带预编译二进制文件,因此终端用户无需安装工具链。 -
Linux x64 — 从 v0.2 起支持。原生辅助程序位于
native/linux/(CMake + GCC);标准 UVC 控件(变焦、对焦、曝光、平移/倾斜、白平衡、图像控制)使用 V4L2,厂商扩展单元命令(云台速度/AI 跟踪、唤醒/休眠、HDR、FOV)使用UVCIOC_CTRL_QUERY。快照通过 V4L2 mmap 流捕获 MJPEG 或 YUYV 帧,并使用 libjpeg 编码为 JPEG。已发布的 npm 包附带linux-x64预编译二进制文件。构建依赖项:build-essential cmake libjpeg-dev libv4l-dev。云台位置读取(
obsbot_gimbal_position)反映的是最近一次命令的位置,而非实时运动中的位置——原因及解决方法见下文的"Linux 云台位置反馈不是实时的"。 -
macOS 14+(Apple Silicon 和 Intel) — 支持。原生辅助程序位于
native/macos/(Objective-C + IOKit/AVFoundation)。标准 UVC 控件和厂商扩展单元命令均通过 IOKit USB 控制传输处理;设备枚举和快照则由 AVFoundation 处理。已发布的 npm 包附带darwin-arm64和darwin-x64预编译二进制文件(darwin-x64也适用于在 Rosetta 下运行 Node 的 Apple Silicon 设备,此时process.arch会报告x64)。最低要求为 macOS 14,因为辅助程序使用AVCaptureDeviceTypeExternal;构建会固定-mmacosx-version-min,确保二进制文件不会继承构建机器的操作系统版本作为最低要求。macOS 特别说明:
UVCAssistant(DriverKit 系统扩展)独占摄像头的 UVC 接口,因此USBInterfaceOpen— 甚至USBInterfaceOpenSeize— 都会因kIOReturnExclusiveAccess而失败。因此,辅助程序会打开未被锁定的 USB 设备,并通过其默认控制端点发送 UVC 控制请求。这与UVCAssistant共存:摄像头受控时仍能像普通网络摄像头一样正常工作,因此无需替换驱动程序。
构建原生辅助程序(Linux)
cd native/linux
mkdir build && cd build
cmake ..
make -j$(nproc)
make install # copies to native/prebuilt/linux-x64/
Linux 云台位置反馈不是实时的
Linux 上的 obsbot_gimbal_position 报告的是最近一次由 obsbot_gimbal_move/
obsbot_gimbal_recenter 命令的位置,而不是运动过程中的实时读数。硬件测试(2026-07-21)
证实,OBSBOT Tiny 2 的 CT_PANTILT_ABSOLUTE 控件确实会跟踪实时位置——绕过内核直接读取
同一控件的原始 USB 数据,显示正在进行的转动会实时推进。普通 V4L2(VIDIOC_G_CTRL)无法看到这一点,
原因是 uvcvideo 会缓存该控件的值,并返回缓存,而不是重新查询设备(通过
VIDIOC_QUERY_EXT_CTRL 确认,该控件没有 V4L2_CTRL_FLAG_VOLATILE 标志)。当设备发送 UVC 控件变更中断时,
驱动会使该缓存失效——但这款摄像头的固件从未发送过这种中断,也从未声明支持该功能。
要通过 V4L2 获取真正的实时读数,必须暂时将内核驱动从摄像头的控件接口分离,然后通过原始 USB 直接读取控件; 但分离该接口(即使只是暂时分离,即使不写入任何内容)也会中断此设备上同时进行的视频采集:流传输和控件共用 一个由内核管理的 USB 功能,因此卸载其中一项的驱动会同时中断两者。这意味着,基于 libusb 的变通方案无法与 同时实际将摄像头用作网络摄像头的场景兼容,因此不能将其作为发布版本的默认方案。
已向上游提交内核补丁(media: uvcvideo: query pan/tilt position from the device on every read,
2026 年 7 月——等待审核,尚未合并)。该补丁将 CT_PANTILT_ABSOLUTE 标记为易变控件,使驱动在每次读取时都查询设备;
已在此硬件上验证,通过普通的 VIDIOC_G_CTRL 即可跟踪实时转动,且不会中断流传输。如果补丁被接受,Linux 上的
obsbot_gimbal_position 就能实时工作,无需在此处更改代码。在补丁进入你所用的内核之前:
obsbot_gimbal_move和obsbot_gimbal_recenter可正常工作——已通过直接写入 V4L2VIDIOC_S_CTRL反复进行硬件验证。 发送前会确定并限制它们的目标值,因此无论是否缺少反馈,都不会超出云台的机械行程范围。- Linux 上无法使用
obsbot_gimbal_move_speed(会完全从工具列表中隐藏,而不只是在运行时拒绝调用)。速度 × 持续时间的连续移动没有可供限制的目标位置——没有实时读数来确认云台的实际位置,就无法在到达机械限位之前约束其运动范围。Windows/macOS 上仍可使用此工具。
构建原生辅助程序(macOS)
make -C native/macos # -> native/prebuilt/darwin-arm64/obsbot-helper
需要 Xcode 命令行工具。也可以使用 CMake(cmake -S native/macos -B native/macos/build && cmake --build native/macos/build),CI 使用的就是这种方式。
已知限制
实际在硬件上测试过的内容,以及尚未测试的内容:
| 平台 | 状态 |
|---|---|
win32-x64 | 硬件验证通过 —— 在真实的 Tiny 2 上验证了会话中途断连恢复(ERROR_DEV_NOT_EXIST,经过实测而非猜测)、摄像头接入/移除推送事件、在不调用工具的情况下主动重新绑定到同一端口重新插拔的摄像头、白平衡以及 ProcAmp 控件范围。重新插拔到不同端口时,会在下一次工具调用时恢复,而非主动恢复——详见下文 |
linux-x64 | 硬件验证通过 —— 通过 V4L2 控制云台绝对移动和回中(在实时预览运行期间连续移动 20 次),并通过实际摆动确认了角秒缩放修复。云台位置不会实时更新,且 obsbot_gimbal_move_speed 不可用——详见下文 |
darwin-arm64 | 硬件验证通过 —— 在真实的 Tiny 2 上验证了控制、云台移动及各轴位置读回、变焦、快照、USB vid/pid 候选识别、序列号读回及按序列号绑定、单所有者 IPC 协调、辅助进程崩溃恢复,以及无需辅助即可从拔出/重新插入中恢复 |
darwin-x64 | 仅构建验证通过 —— 可使用正确的架构和部署目标编译,但从未执行 |
-
Intel(
darwin-x64)辅助程序从未运行过。 没有可用的 Intel Mac 来测试它。它可以顺利交叉编译并打包,但尚无任何验证能确认它可以与摄像头通信。它也适用于在 Rosetta 下运行 Node 的 Apple Silicon 设备,此时process.arch会报告x64,这一情况同样未经测试。欢迎 Intel 用户反馈。 -
需要 macOS 14 或更高版本,且 macOS 运行时仅在 26.5 上经过验证。该辅助程序使用
AVCaptureDeviceTypeExternal(macOS 14+),因此构建时固定使用-mmacosx-version-min=14.0。二进制文件可以在 14 到 25 上加载,但这些版本上的行为未经测试——尤其是 UVC 控制路径依赖UVCAssistant在保持摄像头的 UVC 接口打开的同时,让 USB 设备本身仍可打开。当前 macOS 的行为就是如此;更早版本尚未确认。 -
在 macOS 上拍摄第一张快照时会弹出摄像头权限提示。 该辅助程序是没有捆绑标识符的普通 CLI 工具,因此 macOS 会将摄像头访问权限归属于启动它的应用——也就是你的 MCP 客户端;提示中会显示该应用的名称,授权也会授予该应用。批准一次即可;即使更新辅助程序,授权仍会保留,因为授权是与客户端关联的,而非与辅助程序的签名关联。
-
AI 跟踪会覆盖云台的手动移动。 AI 跟踪处于活动状态时(Tiny 2 唤醒后的默认状态),云台会执行指令进行平移/倾斜,然后又被拉回到跟踪的对象上——
obsbot_gimbal_position会显示偏航/俯仰移出后逐渐回到静止位置。这是摄像头本身的行为,并非故障;关闭跟踪即可不受干扰地手动控制。 -
摄像头可能无法通过 USB 集线器或扩展坞枚举。 通过 USB-C 扩展坞连接的 Tiny 2 在
ioreg和system_profiler中完全不可见——不仅对本服务不可见。如果obsbot_devices返回空结果,请先尝试直接连接,再判断是否为软件故障。 -
仅支持 OBSBOT Tiny 2。 在 Windows 和 macOS 上,候选设备必须同时具有 Remo USB 厂商 ID 和已知型号的产品 ID(
0x3564/0xFEF8),因此完全不会检测到其他型号——名称匹配的软件源(例如 OBSBOT Center 注册的“OBSBOT Virtual Camera”)也会被拒绝,因为它不会报告 vid/pid。Linux 目前仍按名称匹配,因为其辅助程序尚未报告 vid/pid,所以在那里可能会找到其他 OBSBOT 型号——但无论如何,厂商命令集都只适用于 Tiny 2。(在 macOS 上,虚拟摄像头根本不会出现:辅助程序通过 IORegistry 枚举 USB 设备,而软件摄像头不会进入其中。) -
重新插拔后,厂商回复邮箱在几秒内都不可靠。 2026-07-21,观察到一台 Tiny 2 在厂商回复邮箱(XU selector 2)中只返回主机自身回显的请求帧——幻数字节
0xaa被清零为0x00,其他每个字节都相同——持续了 3.2 秒。readSerial()抛出异常,bind()未找到序列号,而所有需要绑定摄像头的工具都报错“no OBSBOT camera found”,尽管设备显然正常:vid/pid 正确、可以正常打开、XU 节点为 2,且 selector 6 上有实时状态块。这一现象曾一度无法解释。现在已能复现:USB 重新枚举后立即出现。在重新插拔期间每隔 50 ms 调用一次
readSerial,前 14 秒内的 80 次尝试中有 22 次失败;而稳定状态下 120 次尝试中 0 次失败。设备出现后的第一次读取恰好显示了上述请求回显特征,之后的失败则显示回复槽已填入数据,但幻数字节仍为零。已排除的原因包括:每个进程中残留的设备状态(同一个长期运行的辅助程序在 t+49 ms 成功读取了全新的唯一 ID)、重新打开设备(两种情况下均为 0/40),以及每种传输方式的序列计数器重置为 1(0/80)。 对调用方的影响:重新插接后的最初几秒内尝试绑定可能会失败,即使摄像头本身正常。重试即可成功。出于这个原因,现在到达事件触发的重新绑定会按有界梯度重试;readSerial失败时会报告邮箱中实际存放的内容(回显的请求/无法解析的内容/对另一个请求的回复),而不再只是报告“没有有效回复”。 此前已排除、现在仍排除的原因包括:回复延迟(轮询了 3.2 秒)、扩展单元错误(VideoControl 接口恰好只公开一个扩展单元,即bUnitID 2)、wLength错误(通过GET_LEN确认每个 XU 选择器都是 60 字节)、回复经由其他选择器到达(已扫描 1–19)、摄像头休眠状态,以及 OBSBOT Center 导致的争用。 -
重新插接后的恢复会主动进行,但并非每种情况都如此,而且不同平台的表现不同。 服务会订阅操作系统的摄像头到达/移除事件,因此在常见情况下,重新插接的摄像头会自行重新绑定,无需调用工具——
obsbot_devices会自动再次报告其状态为bound。下表中的每种情况都经过硬件实测:场景 macOS Windows Linux 插回同一端口 主动恢复 主动恢复 下次工具调用时恢复 插入不同端口 主动恢复 下次工具调用时恢复 下次工具调用时恢复 标为“下次工具调用时恢复”的情况不会导致设备一直无法使用——后续调用会检测到过时的绑定,清除它并重新绑定。代价是有一次调用会失败,而在这些事件机制出现之前,所有平台的表现都完全如此。Windows 的差异源于其到达事件筛选器要求设备路径必须已枚举,这也能防止将 Tiny 2 的音频接口报告为第二台摄像头;macOS 没有同样的问题,因为它按序列号重新绑定,不考虑路径。Linux 目前尚不会发出任何总线事件。
请注意这与上文邮箱条目的交互:重新插接后立即尝试重新绑定,仍可能导致首次尝试失败,因此服务会按较短的有界梯度重试。
-
双摄像头运行尚未经过硬件验证。
camera选择器和按摄像头划分的设备注册表已通过针对虚拟传输的单元测试套件验证;同时连接两台实体 Tiny 2 的情况尚未在真实硬件上确认(当时没有第二台设备)。无论如何,单摄像头使用不受影响。 -
Linux 云台位置反馈尚不可实时获取,因此
obsbot_gimbal_move_speed在该平台不可用。 请参见上文的“Linux 云台位置反馈尚不可实时获取”——一项从源头修复此问题的内核补丁已提交至上游(2026 年 7 月,等待审查)。obsbot_gimbal_move和obsbot_gimbal_recenter不受影响;硬件验证表明两者都能正常工作。obsbot_aim_at_pixel会受到影响——它依赖实时姿态读数来计算瞄准位置,与obsbot_gimbal_position相同。 -
obsbot_zoom_vendor的倍率比例与相同ratio下的obsbot_zoom_uvc不一致。 在ratio: 2.0时进行的硬件快照对比显示,厂商路径的取景比 UVC 路径更紧。尚未确定这是厂商侧的倍率编码存在比例系数偏差,还是两种变焦控件的物理范围不同——仅凭一次对比无法判断。该问题已单独跟踪;如果需要倍率精确匹配,请使用obsbot_zoom_uvc。
不使用专有 SDK
本项目通过操作系统的标准 UVC 驱动程序栈直接与摄像头的 USB 协议通信,不使用、不链接、不捆绑或分发任何厂商 SDK。协议参考(帧格式、校验和、命令表)请参见 PROTOCOL.md。
工作原理
摄像头提供两个彼此独立的控制接口,均可通过操作系统标准的 UVC (USB Video Class)驱动程序栈访问 — 本项目不会直接与 USB 设备通信,因此操作系统会继续中介访问,同时摄像头在发送命令时仍可作为普通网络摄像头使用:
- 标准 UVC 控件 — 变焦(
CT_ZOOM_ABSOLUTE)、对焦和曝光(IAMCameraControl)、 云台位置回读(UVC Pan/Tilt),以及图像控件和白平衡 (IAMVideoProcAmp)— 均为摄像头内置的 UVC 属性,在 Windows 上通过 DirectShow 控制。 - 厂商命令 — 云台移动、归中、唤醒/休眠、AI 跟踪、HDR 和视场 —
通过摄像头的 UVC 扩展单元发送,在 Windows 上通过
IKsControl::KsProperty操作 XU 的拓扑节点。
两种命令都通过一个小型原生辅助进程(Windows 上为 obsbot-helper.exe,Linux 上为 obsbot-helper)发送。Node 服务会启动该进程,并通过 stdin/stdout 上基于行分隔的 JSON-RPC 协议与其通信。辅助进程是唯一的平台专属部分;编解码器(帧编码、CRC-16/USB 校验和、命令表)、传输抽象、设备管理器以及 MCP 工具定义均为纯 TypeScript/JavaScript,可在各平台间共用。
使用真实硬件验证
scripts/e2e.mjs 会使用实体连接的摄像头测试构建后的程序栈(dist/):唤醒设备、放大、转动云台、归中、缩小,然后让摄像头进入休眠。每个步骤执行前都会短暂暂停并输出控制台日志,方便人工观察。此操作会移动实体云台 —
只能在有人监督的情况下运行:
npm run build
node scripts/e2e.mjs
通过实时 MCP 工具测试更改
有两个陷阱很容易让你测错东西,却以为结果正确。2026-07-25,这两个陷阱都浪费了不少时间。
重新构建,然后从新构建启动一个服务。 MCP 服务从 dist/ 运行,因此源代码更改只有在执行 npm run build 后才会生效。本项目通过选出一个唯一的所有者进程来协调并发客户端(参见 IPC-DESIGN.md),而且所有工具调用都由所有者执行,无论调用来自哪个会话。所有者是仍在运行的最新构建:当某个服务从比所有者更新的构建启动时,所有者会完成正在进行的调用,释放摄像头,并将端点交接出去。因此,只需在一个 MCP 客户端中重新加载服务即可。其他会话可以保持打开状态,其调用会由新构建处理。
需要了解以下三点:
- 其他会话的工具列表不会刷新。 在旧构建上启动的会话会保留原有工具列表;但它的调用会运行新代码。重新加载该会话的服务,即可获取新工具。
- 交接发生前启动的服务无法交接(0.7.0 及更早版本)。较新的服务不会在它上面运行调用,并会显示提示:
an older instance owns the camera endpoint and cannot hand it over。只需停止一次旧进程;此后,重新构建会自动接管。 - 使用
npm run build和npm run build:helper。 这两个命令会将构建标识写入文件(dist/build-info.json)。直接运行tsc,或手动复制到位的辅助程序,都不会写入标识,因此不算作较新的构建。
要查看下次调用将由哪个构建处理,请读取服务日志中最后一行 ipc role=。role=owner 表示是此进程;role=client owner-pid=… owner-build=… 则会指出实际处理调用的进程。在 macOS 上,Claude Code 会将日志保存在 ~/Library/Caches/claude-cli-nodejs/<project>/mcp-logs-obsbot/ 下。
# Linux / macOS — every server process, with when it started
ps -o pid,lstart,command -p $(pgrep -f "obsbot.*dist/index.js" | paste -sd, -)
# Windows
Get-CimInstance Win32_Process -Filter "Name='node.exe'" |
Where-Object { $_.CommandLine -like "*Obsbot*" } |
Select-Object ProcessId, CreationDate
设置 OBSBOT_IPC_NAME,即可为服务指定独立的会合端点(1–64 个字符,可使用 A-Z a-z 0-9 . _ -)。测试框架会这样做,以免影响正在运行的会话。同一台机器上的两个所有者可能会争用摄像头,因此不建议日常使用。
帧率决定视野,因此预览画面比快照显示的范围更小。 在 1920×1080 下,这台摄像头在传感器上有两个不同的成像窗口,选择使用哪个窗口的是帧率,而不是编解码器。在一个姿态和一个变焦级别下测量时,MJPEG@30 与 YUYV@30 的比例为 1.00001,2382 个内点,即两者的视野相差不到五分之一像素;而 MJPEG@60 则是二者的 1.214× 裁剪视野。obsbot_capture_preview 固定使用 60fps 以保持画面流畅,因此它比协商为 1080p30 的 obsbot_capture_snapshot 少显示约 21% 的房间范围。凭预览画面目测取景,再根据快照中的像素进行瞄准,两者不会一致。几何常量描述的是 30fps 的视野。所有测量都必须注明像素格式和帧率;仅凭分辨率或编解码器都无法确定视野。
预览会占用摄像头流,因此打开预览时快照会失败。 obsbot_capture_preview 和 obsbot_capture_snapshot 都需要设备流;在 Windows 上,后者会报错 Camera is in use by another application。这会影响上面的瞄准循环,即“快照 → 瞄准 → 快照”:每次拍摄快照前都要停止预览,或者不使用预览。云台控制不受影响——它使用控制传输,而不是视频流——所以即使预览正在运行,obsbot_aim_at_pixel 也能正常工作。错误文本建议使用 source: "virtual" 或 "ndi" 作为变通方案。用于查看时这样做是安全的;用于瞄准时,只有在画面是未经修改的摄像头直通画面时才安全——在 obsbot_aim_at_pixel / obsbot_zoom_to_fit 上通过 source 参数声明,并读取它返回的 note。会对画面进行缩放或添加黑边的合成器会悄无声息地使几何信息失效。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。