reachy-blocks / src /robot /multiplex.ts
Claude
feat: RealRobotAdapter, multiplex fan-out, full embed wiring
aa2dcd1 unverified
Raw
History Blame Contribute Delete
1.72 kB
// Fan-out adapter: drives the on-screen puppet and the real robot in
// lock-step (same targets, same durations, so they stay visually in
// sync). The command log lives here in embed mode — one entry per
// program action regardless of how many robots execute it.
import type { CommandLog } from "../util/log";
import type {
LoadedEmotion,
LoadedSound,
PoseTargetDeg,
RobotAdapter,
} from "./adapter";
export class MultiplexAdapter implements RobotAdapter {
readonly kind = "multi" as const;
constructor(
private children: RobotAdapter[],
private log?: CommandLog,
) {}
async goto(target: PoseTargetDeg, durationSec: number, signal?: AbortSignal): Promise<void> {
this.log?.push("goto", { target, durationSec });
await Promise.all(this.children.map((c) => c.goto(target, durationSec, signal)));
}
async playEmotion(emotion: LoadedEmotion, signal?: AbortSignal): Promise<void> {
this.log?.push("playEmotion", { id: emotion.id });
await Promise.all(this.children.map((c) => c.playEmotion(emotion, signal)));
}
async playSound(sound: LoadedSound, signal?: AbortSignal): Promise<void> {
this.log?.push("playSound", { id: sound.id });
await Promise.all(this.children.map((c) => c.playSound(sound, signal)));
}
antennaTouched(): boolean {
return this.children.some((c) => c.antennaTouched());
}
async stopAll(): Promise<void> {
this.log?.push("stopAll");
await Promise.all(this.children.map((c) => c.stopAll()));
}
async returnHome(): Promise<void> {
this.log?.push("returnHome");
await Promise.all(this.children.map((c) => c.returnHome()));
}
dispose(): void {
for (const c of this.children) c.dispose();
}
}