Spaces:
Sleeping
Sleeping
| # LeRobot Arena JavaScript/TypeScript Client | |
| A modern TypeScript/JavaScript client library for LeRobot Arena robotics system, providing real-time communication for robot control and monitoring. | |
| ## Features | |
| - π€ **Producer/Consumer Pattern**: Control robots as producer, monitor as consumer | |
| - π **Real-time Communication**: WebSocket-based bidirectional communication | |
| - π‘ **REST API Support**: Complete CRUD operations for rooms and state | |
| - π― **Type Safety**: Full TypeScript support with comprehensive type definitions | |
| - π¨ **Safety Features**: Emergency stop functionality built-in | |
| - π§ **Modular Design**: Import only what you need | |
| - π§ͺ **Well Tested**: Comprehensive test suite with Bun test | |
| ## Installation | |
| ```bash | |
| # Install the package (when published) | |
| npm install lerobot-arena-client | |
| # Or for local development | |
| git clone <repository> | |
| cd client/js | |
| bun install | |
| bun run build | |
| ``` | |
| ## Quick Start | |
| ### Producer (Robot Controller) | |
| ```typescript | |
| import { RoboticsProducer, createProducerClient } from 'lerobot-arena-client'; | |
| // Method 1: Manual setup | |
| const producer = new RoboticsProducer('http://localhost:8000'); | |
| const roomId = await producer.createRoom(); | |
| await producer.connect(roomId); | |
| // Method 2: Factory function (recommended) | |
| const producer = await createProducerClient('http://localhost:8000'); | |
| // Send robot commands | |
| await producer.sendJointUpdate([ | |
| { name: 'shoulder', value: 45.0 }, | |
| { name: 'elbow', value: -30.0 } | |
| ]); | |
| // Send complete state | |
| await producer.sendStateSync({ | |
| base: 0.0, | |
| shoulder: 45.0, | |
| elbow: -30.0, | |
| wrist: 0.0 | |
| }); | |
| // Emergency stop | |
| await producer.sendEmergencyStop('Safety stop triggered'); | |
| ``` | |
| ### Consumer (Robot Monitor) | |
| ```typescript | |
| import { RoboticsConsumer, createConsumerClient } from 'lerobot-arena-client'; | |
| // Connect to existing room | |
| const consumer = await createConsumerClient(roomId, 'http://localhost:8000'); | |
| // Set up event listeners | |
| consumer.onJointUpdate((joints) => { | |
| console.log('Joints updated:', joints); | |
| }); | |
| consumer.onStateSync((state) => { | |
| console.log('State synced:', state); | |
| }); | |
| consumer.onError((error) => { | |
| console.error('Error:', error); | |
| }); | |
| // Get current state | |
| const currentState = await consumer.getStateSyncAsync(); | |
| ``` | |
| ## API Reference | |
| ### Core Classes | |
| #### `RoboticsClientCore` | |
| Base class providing common functionality: | |
| ```typescript | |
| // REST API methods | |
| await client.listRooms(); | |
| await client.createRoom(roomId?); | |
| await client.deleteRoom(roomId); | |
| await client.getRoomInfo(roomId); | |
| await client.getRoomState(roomId); | |
| // Connection management | |
| await client.connectToRoom(roomId, role, participantId?); | |
| await client.disconnect(); | |
| client.isConnected(); | |
| client.getConnectionInfo(); | |
| // Utility | |
| await client.sendHeartbeat(); | |
| ``` | |
| #### `RoboticsProducer` | |
| Producer-specific functionality: | |
| ```typescript | |
| const producer = new RoboticsProducer('http://localhost:8000'); | |
| // Connection | |
| await producer.connect(roomId, participantId?); | |
| // Commands | |
| await producer.sendJointUpdate(joints); | |
| await producer.sendStateSync(state); | |
| await producer.sendEmergencyStop(reason?); | |
| // Static factory | |
| const producer = await RoboticsProducer.createAndConnect(baseUrl, roomId?, participantId?); | |
| ``` | |
| #### `RoboticsConsumer` | |
| Consumer-specific functionality: | |
| ```typescript | |
| const consumer = new RoboticsConsumer('http://localhost:8000'); | |
| // Connection | |
| await consumer.connect(roomId, participantId?); | |
| // Data access | |
| await consumer.getStateSyncAsync(); | |
| // Event callbacks | |
| consumer.onJointUpdate(callback); | |
| consumer.onStateSync(callback); | |
| consumer.onError(callback); | |
| consumer.onConnected(callback); | |
| consumer.onDisconnected(callback); | |
| // Static factory | |
| const consumer = await RoboticsConsumer.createAndConnect(roomId, baseUrl, participantId?); | |
| ``` | |
| ### Factory Functions | |
| ```typescript | |
| import { createClient, createProducerClient, createConsumerClient } from 'lerobot-arena-client'; | |
| // Generic factory | |
| const client = createClient('producer', 'http://localhost:8000'); | |
| // Specialized factories (auto-connect) | |
| const producer = await createProducerClient('http://localhost:8000', roomId?, participantId?); | |
| const consumer = await createConsumerClient(roomId, 'http://localhost:8000', participantId?); | |
| ``` | |
| ### Type Definitions | |
| ```typescript | |
| interface JointData { | |
| name: string; | |
| value: number; | |
| speed?: number; | |
| } | |
| interface RoomInfo { | |
| id: string; | |
| participants: { | |
| producer: string | null; | |
| consumers: string[]; | |
| total: number; | |
| }; | |
| joints_count: number; | |
| has_producer?: boolean; | |
| active_consumers?: number; | |
| } | |
| interface RoomState { | |
| room_id: string; | |
| joints: Record<string, number>; | |
| participants: { | |
| producer: string | null; | |
| consumers: string[]; | |
| total: number; | |
| }; | |
| timestamp: string; | |
| } | |
| type ParticipantRole = 'producer' | 'consumer'; | |
| type MessageType = 'joint_update' | 'state_sync' | 'heartbeat' | 'emergency_stop' | 'joined' | 'error'; | |
| ``` | |
| ## Examples | |
| The `examples/` directory contains complete working examples: | |
| ### Running Examples | |
| ```bash | |
| # Build the library first | |
| bun run build | |
| # Run producer example | |
| node examples/basic-producer.js | |
| # Run consumer example (in another terminal) | |
| node examples/basic-consumer.js | |
| ``` | |
| ### Example Files | |
| - **`basic-producer.js`**: Complete producer workflow | |
| - **`basic-consumer.js`**: Interactive consumer example | |
| - **`room-management.js`**: REST API operations | |
| - **`producer-consumer-demo.js`**: Full integration demo | |
| ## Development | |
| ### Prerequisites | |
| - [Bun](https://bun.sh/) >= 1.0.0 | |
| - LeRobot Arena server running on `http://localhost:8000` | |
| ### Setup | |
| ```bash | |
| # Clone and install | |
| git clone <repository> | |
| cd client/js | |
| bun install | |
| # Development build (watch mode) | |
| bun run dev | |
| # Production build | |
| bun run build | |
| # Run tests | |
| bun test | |
| # Type checking | |
| bun run typecheck | |
| # Linting | |
| bun run lint | |
| bun run lint:fix | |
| ``` | |
| ### Testing | |
| The library includes comprehensive tests: | |
| ```bash | |
| # Run all tests | |
| bun test | |
| # Run specific test files | |
| bun test tests/producer.test.ts | |
| bun test tests/consumer.test.ts | |
| bun test tests/integration.test.ts | |
| bun test tests/rest-api.test.ts | |
| # Run tests with coverage | |
| bun test --coverage | |
| ``` | |
| ### Project Structure | |
| ``` | |
| client/js/ | |
| βββ src/ | |
| β βββ index.ts # Main entry point | |
| β βββ robotics/ | |
| β β βββ index.ts # Robotics module exports | |
| β β βββ types.ts # TypeScript type definitions | |
| β β βββ core.ts # Base client class | |
| β β βββ producer.ts # Producer client | |
| β β βββ consumer.ts # Consumer client | |
| β β βββ factory.ts # Factory functions | |
| β βββ video/ # Video module (placeholder) | |
| β βββ audio/ # Audio module (placeholder) | |
| βββ tests/ | |
| β βββ producer.test.ts # Producer tests | |
| β βββ consumer.test.ts # Consumer tests | |
| β βββ integration.test.ts # Integration tests | |
| β βββ rest-api.test.ts # REST API tests | |
| βββ examples/ | |
| β βββ basic-producer.js # Producer example | |
| β βββ basic-consumer.js # Consumer example | |
| β βββ README.md # Examples documentation | |
| βββ dist/ # Built output | |
| βββ package.json | |
| βββ tsconfig.json | |
| βββ vite.config.ts | |
| βββ README.md | |
| ``` | |
| ## Error Handling | |
| The client provides comprehensive error handling: | |
| ```typescript | |
| // Connection errors | |
| try { | |
| await producer.connect(roomId); | |
| } catch (error) { | |
| console.error('Connection failed:', error.message); | |
| } | |
| // Operation errors | |
| producer.onError((error) => { | |
| console.error('Producer error:', error); | |
| }); | |
| // Network timeouts | |
| const options = { timeout: 10000 }; // 10 seconds | |
| const client = new RoboticsProducer('http://localhost:8000', options); | |
| ``` | |
| ## Configuration | |
| ### Client Options | |
| ```typescript | |
| interface ClientOptions { | |
| timeout?: number; // Request timeout (default: 5000ms) | |
| reconnect_attempts?: number; // Auto-reconnect attempts (default: 3) | |
| heartbeat_interval?: number; // Heartbeat interval (default: 30000ms) | |
| } | |
| const producer = new RoboticsProducer('http://localhost:8000', { | |
| timeout: 10000, | |
| reconnect_attempts: 5, | |
| heartbeat_interval: 15000 | |
| }); | |
| ``` | |
| ## Troubleshooting | |
| ### Common Issues | |
| 1. **Connection Failed**: Ensure the server is running on `http://localhost:8000` | |
| 2. **Import Errors**: Make sure you've built the library (`bun run build`) | |
| 3. **Room Not Found**: Check that the room ID exists | |
| 4. **Permission Denied**: Only one producer per room is allowed | |
| 5. **WebSocket Errors**: Check firewall settings and network connectivity | |
| ### Debug Mode | |
| Enable detailed logging: | |
| ```typescript | |
| // Set up detailed error handling | |
| producer.onError((error) => { | |
| console.error('Detailed error:', error); | |
| }); | |
| // Monitor connection events | |
| producer.onConnected(() => console.log('Connected')); | |
| producer.onDisconnected(() => console.log('Disconnected')); | |
| ``` | |
| ### Performance Tips | |
| - Use the factory functions for simpler setup | |
| - Batch joint updates when possible | |
| - Monitor connection state before sending commands | |
| - Implement proper cleanup in your applications | |
| ## Contributing | |
| 1. Fork the repository | |
| 2. Create a feature branch: `git checkout -b feature/amazing-feature` | |
| 3. Make your changes and add tests | |
| 4. Run the test suite: `bun test` | |
| 5. Commit your changes: `git commit -m 'Add amazing feature'` | |
| 6. Push to the branch: `git push origin feature/amazing-feature` | |
| 7. Open a Pull Request | |
| ## License | |
| MIT License - see LICENSE file for details | |
| ## Support | |
| - π [Documentation](./examples/README.md) | |
| - π [Issue Tracker](https://github.com/lerobot-arena/lerobot-arena/issues) | |
| - π¬ [Discussions](https://github.com/lerobot-arena/lerobot-arena/discussions) | |