blanchon's picture
Initial commit
02eac4b

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

# 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)

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)

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:

// 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:

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:

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

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

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

# 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 >= 1.0.0
  • LeRobot Arena server running on http://localhost:8000

Setup

# 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:

# 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:

// 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

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:

// 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