Spaces:
Running
Running
| /** | |
| * Helper to find the USB port associated with your MotorsBus. | |
| * | |
| * Example: | |
| * ``` | |
| * npx lerobot find-port | |
| * ``` | |
| */ | |
| import { SerialPort } from "serialport"; | |
| import { createInterface } from "readline"; | |
| import { platform } from "os"; | |
| import { readdir } from "fs/promises"; | |
| import { join } from "path"; | |
| /** | |
| * Find all available serial ports on the system | |
| * Mirrors Python's find_available_ports() function | |
| */ | |
| async function findAvailablePorts(): Promise<string[]> { | |
| if (platform() === "win32") { | |
| // List COM ports using serialport library (equivalent to pyserial) | |
| const ports = await SerialPort.list(); | |
| return ports.map((port) => port.path); | |
| } else { | |
| // List /dev/tty* ports for Unix-based systems (Linux/macOS) | |
| try { | |
| const devFiles = await readdir("/dev"); | |
| const ttyPorts = devFiles | |
| .filter((file) => file.startsWith("tty")) | |
| .map((file) => join("/dev", file)); | |
| return ttyPorts; | |
| } catch (error) { | |
| // Fallback to serialport library if /dev reading fails | |
| const ports = await SerialPort.list(); | |
| return ports.map((port) => port.path); | |
| } | |
| } | |
| } | |
| /** | |
| * Create readline interface for user input | |
| * Equivalent to Python's input() function | |
| */ | |
| function createReadlineInterface() { | |
| return createInterface({ | |
| input: process.stdin, | |
| output: process.stdout, | |
| }); | |
| } | |
| /** | |
| * Prompt user for input and wait for response | |
| * Equivalent to Python's input() function | |
| */ | |
| function waitForInput(prompt: string = ""): Promise<string> { | |
| const rl = createReadlineInterface(); | |
| return new Promise((resolve) => { | |
| if (prompt) { | |
| process.stdout.write(prompt); | |
| } | |
| rl.on("line", (answer) => { | |
| rl.close(); | |
| resolve(answer); | |
| }); | |
| }); | |
| } | |
| /** | |
| * Sleep for specified milliseconds | |
| * Equivalent to Python's time.sleep() | |
| */ | |
| function sleep(ms: number): Promise<void> { | |
| return new Promise((resolve) => setTimeout(resolve, ms)); | |
| } | |
| /** | |
| * Main find port function - direct port of Python find_port() | |
| * Maintains identical UX and messaging | |
| */ | |
| export async function findPort(): Promise<void> { | |
| console.log("Finding all available ports for the MotorsBus."); | |
| const portsBefore = await findAvailablePorts(); | |
| console.log("Ports before disconnecting:", portsBefore); | |
| console.log( | |
| "Remove the USB cable from your MotorsBus and press Enter when done." | |
| ); | |
| await waitForInput(); | |
| // Allow some time for port to be released (equivalent to Python's time.sleep(0.5)) | |
| await sleep(500); | |
| const portsAfter = await findAvailablePorts(); | |
| const portsDiff = portsBefore.filter((port) => !portsAfter.includes(port)); | |
| if (portsDiff.length === 1) { | |
| const port = portsDiff[0]; | |
| console.log(`The port of this MotorsBus is '${port}'`); | |
| console.log("Reconnect the USB cable."); | |
| } else if (portsDiff.length === 0) { | |
| throw new Error( | |
| `Could not detect the port. No difference was found (${JSON.stringify( | |
| portsDiff | |
| )}).` | |
| ); | |
| } else { | |
| throw new Error( | |
| `Could not detect the port. More than one port was found (${JSON.stringify( | |
| portsDiff | |
| )}).` | |
| ); | |
| } | |
| } | |
| /** | |
| * CLI entry point when called directly | |
| */ | |
| if (import.meta.url === `file://${process.argv[1]}`) { | |
| findPort().catch((error) => { | |
| console.error(error.message); | |
| process.exit(1); | |
| }); | |
| } | |