fibril_can Web マスター (TypeScript / gs_usb)
ROS 2 を介さずにブラウザ・Node から gs_usb 経由で fibril_can スレーブを駆動する TS 実装。C++ bridge と並列の独立コードベース
要点: fibril_can_web は C++ の fibril_can_bridge と同じワイヤプロトコルを TypeScript で並列実装した master 経路。ブラウザや Node から gs_usb 互換の USB-CAN デバイス (Web Serial / WebUSB) で CAN FD を直接読み書きする。ラボ用デバッグ UI、教育用ダッシュボード、Web 製御コンソール用途。
パッケージ構成 (pnpm monorepo)
| パッケージ | 種別 | 中身 |
|---|---|---|
@fibril/can-transport | ライブラリ | ITransport 抽象。raw CAN frame TX/RX のみ、fibril_can セマンティクスなし |
@fibril/can-transport-gsusb | ライブラリ | gs_usb 互換の ITransport 実装 (Web Serial / WebUSB) |
@fibril/can-transport-mock | ライブラリ | プロセス内ループバック (test 用) |
@fibril/can-core | ライブラリ | TS 側のワイヤ+IR 単一正本。protocol 定数 / Extended ID codec / scalar pack / DLC / 設定プレーン / schema 復号 / SHA-256 / 採番 / NodeAgent / MasterController / DataPlaneReceiver / ServiceClient / TypedService / TypedParam / SchemaIndex / frame_planner |
apps/sniffer | React app | listen-only スニッファ UI |
apps/master | React app | アクティブマスター UI。MasterController を駆動 |
依存方向:
transport ─▶ transport-gsusb / -mock
│
▼
@fibril/can-core
│
▼
apps/sniffer apps/master@fibril/can-core だけがワイヤ + IR を知る。transport はフレームだけ、apps は core の API を呼ぶだけ。C++ 側 fibril_can_core と対をなす二重実装で、両方が SPEC を独立に実装する。
クイックスタート (スニッファ、listen-only)
cd fibril_can_web
pnpm install
pnpm dev:snifferVite dev server → ブラウザで gs_usb デバイス選択 → bitrate 設定 → 接続。手動 schema.blob ロードで S→M Topic を std_id にピン止めしてフィールドを decode 表示。バスに送信しないので、他 master が走ってても安全。
クイックスタート (アクティブマスター UI)
pnpm dev:master # http://localhost:5174gs_usb デバイス選択で MasterController が起動、以下を自動で回す:
start()直後に 1 回 broadcast DISCOVER (前 master の残骸を一掃、initialDiscover: falseで抑止)- MASTER_HEARTBEAT 周期送出 (既定 100ms)
- ANNOUNCE / HEARTBEAT を受けたスレーブに対する
NodeAgent自動 spawn - spawn 後
defaultS2MFramePlanで S→M 全 Topic 購読の FRAME_DEFINE → START
broadcast DISCOVER は破壊的 (SPEC §5.11、受信スレーブの frame table wipe → UNPROVISIONED)。周期送出は既定 OFF (discoverPeriodMs: 0)。遅れて起動したスレーブは自身の起動時 spontaneous ANNOUNCE × 3 でほぼ拾える。補助的な再探索は UI の Discover ボタン。
UI の 8 タブ
| タブ | 内容 |
|---|---|
| Overview | spawn 済みスレーブ一覧 (state バッジ / boot_id / schema_hash / HEARTBEAT 鮮度)、autostart トグル、Start ボタン |
| Schema | 選択スレーブの Topics / Services / Params (field 型 / wire size / default) |
| Frames | FramePlan を 1 frame=1 card。std_id / dir / period、packed entries の byte レイアウト可視化 |
| Topics | S→M ライブ値 (dict + rate Hz、10 Hz ポーリング) + M→S 定義。field 単位の on/off、Apply で FRAME_DEFINE 打ち直し |
| Services | request エディタ → Call → response + status。Trigger 形は Call ボタンのみ |
| Params | default 初期値の編集フォーム → Set → SVC_PARAM_SET の status / failedIndex |
| Graphs | S→M 数値フィールドの multiselect + uPlot、30 Hz サンプル、window 5s〜3m |
| Raw CAN | transport tee の 5000 件リングバッファ、fibril ext-ID を CFG ANNOUNCE node=0x10 seq=3 形式に decode |
プログラム経由 (単体 NodeAgent)
import { connectGsUsb } from '@fibril/can-transport-gsusb';
import { NodeAgent, MasterHeartbeatBroadcaster, defaultS2MFramePlan }
from '@fibril/can-core';
const transport = await connectGsUsb({ bitrate: 1_000_000, dataBitrate: 5_000_000 });
await transport.open();
const heartbeat = new MasterHeartbeatBroadcaster(transport, 100);
heartbeat.start();
const agent = new NodeAgent({
nodeId: 0x10,
transport,
framePlan: (schema, numbering) => defaultS2MFramePlan(schema, numbering),
onState: (s) => console.log('state', s),
});
await agent.start();
// state.kind === 'running' 後に snapshot が読める
const snap = agent.snapshot!;
const setPid = snap.service<{kp: number}, {accepted: boolean}>('motor0/set_pid');
const r = await setPid.call({ kp: 1.5 }, { timeoutMs: 250 });
// param set は SVC_PARAM_SET (0xFD) 経由
await snap.param<number>('motor0/velocity/kp').set(2.0);MasterHeartbeatBroadcaster の使い分け
SPEC §5.11 の MASTER_HEARTBEAT を周期送出するだけの独立コンポーネント。NodeAgent には含まれていない。1 本の transport に複数 NodeAgent を載せるなら broadcaster は 1 つを全 agent で共有。
framePlan のカスタム
defaultS2MFramePlan はスレーブが送る S→M Topic を全 field 購読するデフォルト。一部だけ購読したい / 周期を変えたいなら FieldRequest を直接組み立てて planFrames に渡す。
typed bindings は未着手
schema.blob → TypeScript interface + path のリテラル型の generator は現状ない。TS 側は文字列 path で service / param を呼ぶ。将来やるなら @fibril/can-core から独立パッケージとして生やす想定。
bridge (C++) との使い分け
| 場面 | 推奨 |
|---|---|
| ROS 2 スタックに載せる | C++ fibril_can_bridge |
| ラボ用 GUI / ダッシュボード | Web master (apps/master) |
| 一時的な観測 | Web sniffer (apps/sniffer) |
| CI / スクリプトから駆動 | Node で NodeAgent 直接 |
同じバスに両方の master を同時に載せない (DISCOVER / MASTER_HEARTBEAT が競合)。Web sniffer は listen-only なので併用可。
関連
- fibril_can 概要
- fibril_can 使い方 — C++ bridge 経由の場合