OBSBOT Tiny 2 Camera Control について
OBSBOT Tiny 2をUSB経由、OBSBOT Tail 2をネットワークAPI経由で操作するクロスプラットフォームのMCPサーバーです。カメラの動きや画像設定、追跡、撮影、録画をMCPクライアントから制御できます。
主な機能
- 01ジンバルのパン、チルト、ロール制御
- 02ズーム、フォーカス、露出、ホワイトバランス調整
- 03AIトラッキング、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 クライアントの設定
インストール済みバイナリ(またはdist/index.js)を指定するstdioサーバーのエントリーを追加します。
{
"mcpServers": {
"obsbot": {
"command": "obsbot-mcp"
}
}
}
npmでインストールせず、ローカルのチェックアウトから実行する場合は、command/argsでnodeとビルド済みのエントリーポイントを指定してください。
{
"mcpServers": {
"obsbot": {
"command": "node",
"args": ["path/to/obsbot-mcp/dist/index.js"]
}
}
}
デバッグ/診断ツール
デフォルトでは、サーバーは通常の制御機能のみを公開します。--debugを渡すと、診断機能(生のXUバイトを取得/設定/照会するobsbot_debug_probeツールと、obsbot_statusの生の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はLinuxでは利用できません。詳しくは制限事項を参照してください)。--debugを指定すると、obsbot_debug_probeが追加されます。ネットワーク上のTail 2カメラ1台につき、以下のOBSBOT Tail 2に記載されたobsbot_tail2_*ツールが32個追加されます(全プラットフォーム対応。純粋なTypeScriptで実装されています)。以下に記載した名前はすべてv0.4.0時点のものです。このリリースではすべてのツール名が変更されており、後方互換性のあるエイリアスはありません。呼び出し側を更新する場合は、旧名から新名への完全な対応表をCHANGELOG.mdで確認してください。
cameraセレクター
カメラを指定するすべてのツールには、対象カメラのシリアル番号を指定するオプションのcameraパラメーターがあります。カメラを1台だけ接続している場合は省略しても何も変わらず、サーバーのv0.4.0より前の単一カメラ動作とまったく同じです。複数台接続している状態でcameraを省略した呼び出しを行うと、接続されているすべてのシリアル番号を示すエラーが返るため、次に何を渡せばよいか常に確認できます。
対象外(cameraパラメーターは常にありません):obsbot_devices(全カメラを列挙)、obsbot_capture_stop/obsbot_capture_list(デバイスではなくsessionIdを指定)、obsbot_debug_probe(現在の診断トランスポートを操作)。ほかに2つのツールは一部の動作でのみこのパラメーターに対応します。以下のキャプチャを参照してください。
マルチカメラ対応はv0.4.0で追加されました。ユニットテストスイートではフェイクを使って検証していますが、Tiny 2を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 はマニュアルモードでのみ表示されます。値の範囲は obsbot_focus_manual が使用するものと同じ 0~100 です。オートフォーカス時、カメラはモーターの状態ではなく最後に書き込まれた値を返すため、そこに表示される数値はライブのフォーカス距離のように見えても古い値です。フォーカスはステータスブロックの一部ではなく、標準のUVC制御であるため、読み取りが1回余分に必要です。応答できないデバイスでは呼び出し全体が失敗するのではなく、focusMode: "unknown" が返されます。--debug を指定すると、16進数形式の生の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 度/秒以上ではジンバルはまったく動かないため、指令値はハードウェアで検証済みの範囲内に制限されます。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 は指定した割合だけズームを控えめにし、領域がフレームの端までぴったりに映らないようにします。領域の 2 軸のうち、より狭い方でズームが決まるため、片側が切り取られずに領域全体が表示されます。ズームより先にジンバルを動かします。ズームは中心位置を保ちますが、対象位置は保たないため、先にズームすると領域がフレームから外れる可能性があります。ズームは段階的に変化するため、このツールは最大 3 秒間ポーリングします。時間内にズームが完了していない場合はエラーではなく settled:false を返すため、後続のスナップショットを信頼する前に状態を確認してください。 |
見えている対象を狙う
obsbot_capture_snapshot はフレームを画像として、さらに width/height とともに返すため、モデルは画像内の対象を特定し、その対象にカメラを向けられます。
obsbot_capture_snapshot— フレームを確認しますobsbot_aim_at_pixel— 対象のピクセル座標と、そのフレームの寸法を渡しますobsbot_capture_snapshotを再度実行 — 狙った位置に向いたことを確認し、必要に応じて繰り返します
ピクセル座標を取得したスナップショットと同じものから、frameWidth/frameHeight を渡してください。あるフレームのピクセル座標と別のフレームの寸法を組み合わせると、誤った場所を狙ってしまいますが、それを検出する方法はありません。
スナップショットの source は "device" でなければなりません。 obsbot_capture_snapshot は、カメラの生ストリームではなく OBSBOT Center 独自の出力を取得する "virtual" または "ndi" の source も指定できます。これらの出力はカメラの光学系ではなく 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 はカメラの動きが想定より遅かったことを意味するだけで、何かが失敗したという意味ではありません。
ジンバルのプリセット
デバイス上のプリセットスロットは 3 つ(1~3)です。スロットは一度だけ作成できます。obsbot_preset_save を使うにはスロットが空である必要があります(再利用するには先に削除してください)。ほかのプリセットツールを使うには、スロットがすでに使用中である必要があります。各ツールは書き込み後にスロット一覧を再読み込みし、デバイスに変更が反映されなかった場合は、構造化された { ok:false } の失敗結果を返します。
| ツール | パラメーター | 説明 |
|---|---|---|
obsbot_preset_list | camera? | 3 つのプリセットスロットの状態(使用中/空)、名前、角度単位のポーズを読み取ります。 |
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 で再利用できるようにします。 |
ズーム
ツールは1つではなく2つあります。異なる通信方式(標準UVCとベンダー独自のコマンドフレーム)を使用し、
同じratioを指定しても物理的なズーム量が異なるため、統合するとratioの意味が意図せず変わってしまいます。必要な動作に応じて選択してください。
| Tool | Parameters | Description |
|---|---|---|
obsbot_zoom_uvc | ratio(1.0~2.0)、camera? | 標準UVCズームです。絶対ズーム比を設定し、値は[1.0, 2.0]の範囲に制限されます。指定した目標値に正確に合わせます。ズームが完了するまで待機し、settledを返します。ズームの移行は瞬時ではなく、1.0から2.0までの全範囲の移動には約2.4秒かかります。また、移行中は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 トラッキング
| Tool | Parameters | Description |
|---|---|---|
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ツールに分かれました
(以前はモードパラメーターを持つ1つのツールでした)。自動と手動では必要なパラメーターが異なるため、
分割することで、それぞれのスキーマに必要なパラメーターだけを正確に指定できます。
| Tool | Parameters | Description |
|---|---|---|
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は実装されていません(長さゼロのコントロールとして報告されます)。これらを指定するとエラーとなり、残りの5項目は使用できます。 |
キャプチャ
obsbot_capture_record と obsbot_capture_preview は camera を受け取りません。 シリアル番号ではなく、ffmpeg/ffplay を通じて source(device/virtual/ndi)でデバイスを選択します。シリアル番号と ffmpeg デバイスを対応付ける機能はまだありません。obsbot_capture_snapshot が camera を反映するのは source:"device" の場合のみです。source:"virtual"/"ndi" では、camera に関係なく、デバイス名によってピクセルソースが解決されます。
| ツール | パラメーター | 説明 |
|---|---|---|
obsbot_capture_snapshot | resolution(256~1920、デフォルトは 640)、quality(1~100、デフォルトは 80)、settleMs(0~15000、デフォルトは 600)、source(デフォルトは "device")、camera?(source:"device" のみ) | 静止画を 1 フレーム取得し、画像として返します(フレーミング/照明/露出の確認用)。resolution は長辺のピクセル数です。値を大きくすると、トークン消費も比例して増えます。source:device | virtual | ndi。また、キャプチャグラフでネゴシエートされたフォーマット(例:MJPG [email protected])を示す sourceFormat も返します。このカメラではフレームレートによって視野角が変わるためです(制限事項を参照)。Windows のみです。不明な場合は含まれません。接続が遅延するソース(NDI)では、settleMs を大きくする必要がある場合があります。 |
obsbot_capture_record | durationSec(省略可)、audio(デフォルトは true)、outputPath(省略可)、source(デフォルトは "device") | MP4 への録画を開始します。録画時間を指定しない場合、60 分後に自動停止します。音声には OBSBOT マイクを使用します。すべてのプラットフォームでデフォルトの保存先は ~/Videos/OBSBOT です。通常の保存先が ~/Movies である macOS でも同様です。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 | リバースエンジニアリング/診断専用です。生の 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 ウェブカメラとして動作します。以下のツールは、オンデバイスのリバースエンジニアリングに基づき TAIL2-PROTOCOL.md に記載されている、HTTP REST API と WebSocket ステータスプッシュによるネットワーク制御プレーンを使用します。そのため、モジュール全体がプラットフォーム固有のコードを含まない純粋な TypeScriptで構成されています。ネイティブヘルパーも、ヘルパーのビルドも不要で、Windows/Linux/macOS で同じように動作します。
UVC モードでは、カメラは USB 経由で標準の UVC コントロール(パン、チルト、ズーム、パン/チルト速度、フォーカス、露出、ホワイトバランス)にも応答し、ベンダー拡張ユニットではトラッキングのオン/オフ、人物トラッキングモード、トラッキング速度、自動ズームを利用できます。このサーバーには Tail 2 用の USB トランスポートがまだないため、これらはツールとして公開されていません。プリセット、縦向き回転、ロール補正はネットワーク経由のみです。測定内容については、TAIL2-PROTOCOL.md §11 を参照してください。
始め方:
- Tail 2 をネットワークに接続します(イーサネットではデフォルトで DHCP が有効です)。
obsbot_tail2_scanを一度呼び出します。カメラ独自の mDNS アナウンスを約 5 秒間待ち受けます(数秒おきに MAC アドレス、名前、IP アドレスをマルチキャストします。OBS BOT Center が検出に使用するものと同じチャネルです)。マルチキャストがフィルタリングされるネットワークでのみ、HTTP サブネットスイープにフォールバックします。または、サーバーの環境変数にOBSBOT_TAIL2_HOSTS(カンマ区切りのアドレス)を設定するか、任意の Tail 2 ツールにカメラの IP アドレスを含むcameraパラメーターを渡します。
これらのツールの camera セレクターには、カメラの MAC(安定した識別子)、device_name、またはホストアドレスを指定します。大文字と小文字は区別されません。Tail 2 が 1 台だけ登録されている場合は、省略するとそのカメラが選択されます。
| ツール | パラメーター | 説明 |
|---|---|---|
obsbot_tail2_devices | — | 登録済みのTail 2カメラ(mac、名前、ホスト)を一覧表示します。登録されていることは、稼働中であることを意味しません。 |
obsbot_tail2_scan | — | Tail 2カメラを検出します。約5秒間mDNSをリッスン(カメラ自身によるアナウンス)し、フォールバックとしてHTTPでサブネットをスイープします。検出したカメラを登録します。 |
obsbot_tail2_status | camera? | WebSocketのステータスプッシュを1回取得します。電源、録画、縦向き、AIモードとトラッキング設定、ズーム比、ロールバイアス、フォーカスモード、NDI/RTSP/SRT/RTMPフラグ、SDカード、ポーズ付きプリセット、サブシステムごとのヘルス状態を含む、ライブ情報一式です。ライブのヨー/ピッチ情報はありません。Tail 2のジンバルはオープンループで動作します。 |
obsbot_tail2_info | camera? | 1回の呼び出しでID情報と静的設定を取得します。device_info、range(ズーム 1.0–12.0、フォーカス1–100、WB 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? | ジンバルを再センタリングします(yaw/pitch/roll 0)。オープンループで動作し、確認応答を受け取ると戻ります。AIトラッキングがnoneになる場合があります。obsbot_tail2_ai_trackで再度有効にしてください。 |
obsbot_tail2_gimbal_position | camera? | ジンバルのライブ姿勢を度数(yaw/pitch/roll)とズーム比で取得します。スクラッチ用プリセットの保存→読み取り→削除で実行します(約2秒)。空のプリセットスロットが1つ必要です(プローブ用スロットは自動的に削除されます)。 |
obsbot_tail2_gimbal_speed | yaw? pitch? roll?(速度±150)、durationMs?(100–5000、デフォルト500)、camera? | 自動停止付きでジンバルをジョグ操作します(ジョイスティックの基本操作)。実測値では、コマンド20で約7.9°/秒です。正のyawコマンドでは、記録されるyawが減少します。最初にAIトラッキングを無効にしてください。 |
obsbot_tail2_gimbal_move | yaw? pitch?(±178°)、camera? | クローズドループで絶対位置へ移動します(ジョグ→姿勢読み取り→補正、最大5ラウンド、許容誤差±1.5°)。設計上、低速です(小さな移動でも約1秒、大きな移動ではさらに時間がかかります)。AIトラッキングが有効な間は実行を拒否します。2026-09-30にハードウェア検証済みです。4°の移動は1回の反復で収束しました。 |
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? | フォーカスを読み取るか設定します。positionを指定できるのはmfモードのみです(モードによる制限があり、それ以外ではツールが要求を拒否します)。 |
obsbot_tail2_exposure | mode?、face?、evbias?、iso?、shutter?、camera? | モードに応じた露出を読み取るか設定します。自動(顔優先AE+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? | アクティブなネットワーク出力を1つ読み取るか設定します。obsbot_tail2_snapshotでSRTを有効にするためのプログラムによる方法です。Centerは不要です。 |
obsbot_tail2_only_me | enabled?、camera? | OnlyMe人物トラッキング(全員ではなく1人を追跡)を読み取るか設定します。 |
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範囲を読み取るか設定します(2つのスライダーに対応し、省略した境界値は現在の値が保持されます)。 |
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? | トラッキングの追従速度です。Tiny 2標準のstandard/sportの2段階ではなく、Tail 2独自の6段階の列挙値を使用します。 |
obsbot_tail2_preset_list | camera? | 3つのプリセットスロットについて、使用中/空の状態、デコードした名前、度数表記の姿勢とズーム比を一覧表示します。 |
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? | 静止フレームを1枚取得し、画像として返します。カメラの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 は認証されません。LAN 上の誰でも、電源オフを含めてカメラを操作できます。
対応プラットフォーム
-
Windows x64 — 現在対応しています。ネイティブヘルパーは
native/windows/(CMake + MSVC)でソースからビルドされます。公開 npm パッケージにはビルド済みバイナリが同梱されるため、エンドユーザーにツールチェーンは必要ありません。 -
Linux x64 — v0.2 から対応しています。ネイティブヘルパーは
native/linux/(CMake + GCC)にあります。標準の UVC コントロール(ズーム、フォーカス、露出、パン/チルト、ホワイトバランス、画像制御)にはV4L2を、ベンダーの Extension Unit コマンド(ジンバル速度/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 コントロールとベンダーの Extension Unit コマンドの両方に IOKit の USB 制御転送を使用し、デバイスの列挙とスナップショットの取得には AVFoundation を使用します。公開 npm パッケージにはdarwin-arm64とdarwin-x64の両方のビルド済みバイナリが同梱されます(darwin-x64は、Node を Rosetta 上で実行し、process.archがx64を報告する Apple Silicon にも対応します)。ヘルパーはAVCaptureDeviceTypeExternalを使用するため、macOS 14 が最低要件です。ビルドでは-mmacosx-version-minを指定し、バイナリの最低要件がビルドマシンの OS を引き継がないようにしています。macOS 固有の注意点:DriverKit のシステム拡張機能である
UVCAssistantがカメラの 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 Control Change 割り込みを送信すると、ドライバーはこのキャッシュを無効化しますが、このカメラのファームウェアはその割り込みを送信せず、対応も通知しません。
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は通常どおり動作します。V4L2 のVIDIOC_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 がありませんでした。問題なくクロスコンパイルされ、パッケージ化されていますが、カメラと通信できることは確認されていません。また、Node を Rosetta 経由で実行している 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 Virtual Camera」のように OBSBOT Center が登録する名前の一致するソフトウェアソースも、vid/pid を報告しないため除外されます。Linux ではヘルパーがまだ vid/pid を報告しないため、名前で照合しています。そのため、別の OBSBOT が 見つかる 可能性はありますが、いずれの場合もベンダーコマンドセットは Tiny 2 専用です。(macOS では仮想カメラが表示されることはありません。ヘルパーは IORegistry 経由で USB デバイスを列挙しますが、ソフトウェアカメラは IORegistry に登録されないためです。) -
再接続後、数秒間はベンダー応答メールボックスが不安定です。 2026-07-21、Tiny 2 がベンダー応答メールボックス(XU セレクター 2)から、ホスト自身が送信した要求フレームをエコーバックしたものだけを返す事例が確認されました。マジックバイトの
0xaaが0x00にクリアされ、それ以外のバイトはすべて同一の状態が、連続して 3.2 秒続きました。readSerial()は例外をスローし、bind()はシリアル番号を見つけられず、カメラのバインドが必要なすべてのツールが「no OBSBOT camera found」で失敗しました。一方で、デバイス自体は明らかに正常でした。vid/pid は正しく、正常にオープンでき、XU ノード 2 も確認でき、セレクター 6 のステータスブロックもライブ状態でした。しばらく原因は不明でした。現在は、USB の再列挙直後に発生することが再現可能です。再接続中に
readSerialを 50 ms 間隔でポーリングしたところ、最初の 14 秒間にわたる 80 回の試行のうち 22 回失敗しました。安定稼働時は 120 回中 0 回でした。デバイスの接続後、最初の読み取りでは上記とまったく同じ要求エコーの特徴が現れ、その後の失敗では、応答スロットに値が入っているものの、マジックバイトがゼロのままでした。原因として、プロセスごとに保持される古いデバイス状態(同じ長時間稼働中のヘルパーが t+49 ms に新しい一意の ID を問題なく読み取りました)、デバイスの再オープン(いずれの方法でも 0/40)、およびトランスポートごとのシーケンスカウンターが 1 から再開すること(0/80)は除外されました。 呼び出し側への影響:再接続直後の数秒間に bind を試みると、カメラに問題がなくても失敗することがあります。再試行すれば成功します。このため、接続イベントを起点とする再 bind では、上限付きの段階的な再試行を行うようになりました。また、readSerialの失敗時には、単に「有効な応答なし」と報告するのではなく、メールボックスに実際に格納されていた内容(エコーされたリクエスト/解析不能/別のリクエストへの応答)を報告します。 以前に検証し、現在も原因ではないと確認済みの項目:応答の遅延(3.2 秒間ポーリング)、誤った拡張ユニット(VideoControl インターフェースが公開するユニットはbUnitID 2の 1 つのみ)、誤ったwLength(GET_LENによると、すべての XU セレクターが 60 バイト)、別のセレクターへの応答(1~19 をすべて検証)、カメラのスリープ状態、OBSBOT Center との競合。 -
再接続後の復旧は先回りして行われますが、すべての場合ではなく、プラットフォームによって異なります。 サーバーは OS のカメラ接続/切断イベントを購読しているため、一般的なケースでは、再接続されたカメラはツール呼び出しなしで自動的に再 bind されます。
obsbot_devicesは、カメラが自動的に再びboundになったことを報告します。以下の各セルは、すべてハードウェアで測定済みです。シナリオ macOS Windows Linux 同じポートへの再接続 先回りして復旧 先回りして復旧 次のツール呼び出し時 別のポートへの再接続 先回りして復旧 次のツール呼び出し時 次のツール呼び出し時 「次のツール呼び出し時」とある場合でも、何かが取り残されるわけではありません。次の呼び出しで古いバインドを検出して削除し、再 bind します。失敗する呼び出しが 1 回発生しますが、これはこうしたイベントが導入される前に、どのプラットフォームでも起きていた動作とまったく同じです。Windows で動作が異なるのは、到着イベントのフィルターが、すでに列挙済みのパスを要求するためです。これにより、Tiny 2 の オーディオ インターフェースが 2 台目のカメラとして報告されることも防いでいます。macOS ではシリアル番号で再 bind し、パスを無視するため、同等の問題はありません。Linux では現在、バスイベントが一切発生しません。
上記のメールボックスの項目との関連にも注意してください。再接続直後に試みた再 bind は、最初の試行で失敗することがあります。そのため、サーバーは短い間隔で、上限付きの段階的な再試行を行います。
-
2 台のカメラでの動作は、まだハードウェアで検証されていません。
cameraセレクターとカメラごとのデバイスレジストリーは、偽のトランスポートを使ったユニットテストスイートでカバーされていますが、物理的な Tiny 2 を 2 台同時に接続した動作は、実機では未確認です(2 台目の機器を用意できませんでした)。どちらの場合も、1 台での使用には影響しません。 -
Linux ではジンバルの位置フィードバックがリアルタイムではなく、そのため
obsbot_gimbal_move_speedは利用できません。 上記の「Linux ではジンバルの位置フィードバックがリアルタイムではありません」を参照してください。これを根本から修正するカーネルパッチが上流に提出されています(2026 年 7 月、レビュー待ち)。obsbot_gimbal_moveとobsbot_gimbal_recenterには影響せず、どちらも通常どおり動作することをハードウェアで検証済みです。obsbot_aim_at_pixelには影響があります。obsbot_gimbal_positionと同様、照準の計算にリアルタイムの姿勢読み取りを必要とするためです。 -
同じ
ratioでも、obsbot_zoom_vendorの比率スケールはobsbot_zoom_uvcのものと一致しません。ratio: 2.0でハードウェアのスナップショットを比較したところ、ベンダー経由のパスのほうが UVC 経由のパスよりも画角が狭くなりました。ベンダー側の比率エンコーディングのスケール係数がずれているのか、2 つのズーム制御の物理的な範囲が異なるだけなのかは、まだ特定できていません。比較が 1 回だけでは判断できません。この問題は別途追跡しています。比率を正確に適用する必要がある場合は、obsbot_zoom_uvcを使用してください。
独自 SDK は不使用
このプロジェクトは OS 標準の UVC ドライバースタックを介してカメラの USB プロトコルを直接扱い、ベンダー SDK は使用、リンク、同梱、配布していません。プロトコルのリファレンス(フレーム形式、チェックサム、コマンド表)については、PROTOCOL.md を参照してください。
動作の仕組み
カメラには、OS 標準の UVC(USB Video Class)ドライバースタック経由でどちらも利用できる、独立した 2 つの制御インターフェースがあります。このプロジェクトは USB デバイスと直接通信しないため、OS がアクセスを仲介し続け、コマンドの送信中もカメラを通常のウェブカメラとして使えます。
- 標準 UVC コントロール — ズーム(
CT_ZOOM_ABSOLUTE)、フォーカスと露出(IAMCameraControl)、ジンバル位置の読み取り(UVC Pan/Tilt)、画像コントロールとホワイトバランス(IAMVideoProcAmp)は、カメラに組み込まれた UVC プロパティであり、Windows では DirectShow 経由で制御します。 - ベンダーコマンド — ジンバルの移動、中央位置への復帰、ウェイク/スリープ、AI トラッキング、HDR、視野角は、Windows では XU のトポロジーノードに対する
IKsControl::KsProperty経由で制御する、カメラの UVC Extension Unit を通じて送信します。
どちらも、小さなネイティブヘルパープロセス(Windows では obsbot-helper.exe、Linux では obsbot-helper)を介して実行します。Node サーバーがこのプロセスを起動し、標準入力/標準出力上の行区切り JSON-RPC プロトコルで通信します。プラットフォーム固有の部分はヘルパーのみです。コーデック(フレームエンコーディング、CRC-16/USB チェックサム、コマンドテーブル)、トランスポート抽象化、デバイスマネージャー、MCP ツール定義はすべて純粋な TypeScript/JavaScript で実装され、プラットフォーム間で共有されています。
実機での検証
scripts/e2e.mjs は、ビルド済みのスタック(dist/)を、物理的に接続されたカメラで実行します。デバイスを起動し、ズームイン、ジンバルのパン、中央位置への復帰、ズームアウトを行ってからカメラをスリープさせます。各手順の前に短い一時停止を入れ、コンソールにログを出力するため、人が動作を確認できます。物理的なジンバルが動くため、必ず監視下でのみ実行してください。
npm run build
node scripts/e2e.mjs
ライブ MCP ツールを使って変更をテストする
誤ったものをテストして、その結果を信じてしまいやすい落とし穴が2つあります。どちらも 2026-07-25に実際に時間を無駄にしました。
再ビルドしてから、新しいビルドからサーバーを1つ起動します。 MCP サーバーは
dist/ から実行されるため、npm run build を実行するまではソースの変更は反映されません。このプロジェクトでは
単一のオーナープロセスを選出して、同時に接続するクライアントを調整します(IPC-DESIGN.md を参照)。すべてのツール呼び出しはオーナーが実行します。
どのセッションから呼び出されたかは関係ありません。オーナーは、稼働中の最新ビルドです。新しいビルドからサーバーが起動すると、現在のオーナーは実行中の呼び出しを完了し、カメラを解放して、エンドポイントを引き継ぎます。そのため、1つの MCP クライアントでサーバーを再読み込みするだけで十分です。他のセッションは開いたままでも、呼び出しは新しいビルドによって処理されます。
知っておくべきことは3つあります。
- 他のセッションのツール一覧は更新されません。 古いビルドで起動したセッションには、そのときのツール一覧が残りますが、呼び出しは新しいコードで実行されます。新しいツールを取得するには、そのセッションのサーバーを再読み込みしてください。
- 引き継ぎより前に起動したサーバーは、引き継ぎを実行できません(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 を設定すると、サーバーに専用のランデブーエンドポイントを割り当てられます(A-Z a-z 0-9 . _ - の1〜64文字)。テストハーネスは、稼働中のセッションに干渉しないよう、これを使用します。同じマシン上の2つのオーナーがカメラを取り合う可能性があるため、日常的な使用には適していません。
フレームレートによって視野が決まるため、プレビューではスナップショットよりも見える範囲が狭くなります。 1920×1080では、このカメラはセンサー上の異なる2つの領域を使用し、そのどちらを使うかはコーデックではなくフレームレートで決まります。同じ位置とズームで測定した結果、MJPEG@30 と YUYV@30 は2382個のインライアに対してスケールが1.00001となり、視野は0.2ピクセルの5分の1以内で一致しました。一方、MJPEG@60 ではどちらに対しても1.214倍にクロップされます。
obsbot_capture_preview は滑らかな動きのために60fpsに固定されているため、1080p30をネゴシエートする
obsbot_capture_snapshot よりも、部屋の見える範囲が約21%狭くなります。プレビューを目で見て構図を決めてから、スナップショット上のピクセルを狙っても一致しません。ジオメトリ定数は30fpsの視野を表します。測定値を示す際は、ピクセル形式とフレームレートの両方を明記してください。解像度やコーデックだけでは、視野を特定できません。
プレビュー中はカメラストリームが使用されるため、プレビューを開いたままではスナップショットに失敗します。 obsbot_capture_preview と obsbot_capture_snapshot はどちらもデバイスストリームを必要とし、Windowsでは2つ目の呼び出しで
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 サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。