Spaces:
Running
Running
# 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) | |