File size: 5,607 Bytes
5ed471e
 
 
 
 
 
 
 
 
ae872e1
 
 
 
 
 
 
 
 
9883b81
5ed471e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45fb4ba
5ed471e
 
45fb4ba
5ed471e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45fb4ba
5ed471e
 
45fb4ba
5ed471e
45fb4ba
5ed471e
 
 
 
 
 
 
 
 
 
45fb4ba
5ed471e
45fb4ba
5ed471e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// Import WASM module and functions from npm (published version)
import init, {
    connect,
    enable_torque,
    disable_torque,
    forward_kinematics,
    inverse_kinematics,
    start_fk_stream,
    replay_recording,
    stop,
    // Video Stream (optional - for future use)
    connect_video_stream,
    disconnect_video_stream,
    is_using_camera_fallback,
    // Audio Stream (optional - for future use)
    connect_audio_stream,
    disconnect_audio_stream,
    is_using_microphone_fallback,
} from 'https://unpkg.com/reachy-mini@0.6.1/index.js';

// Elements
const btnConnect = document.getElementById('btn-connect');
const btnTorqueOn = document.getElementById('btn-torque-on');
const btnTorqueOff = document.getElementById('btn-torque-off');
const btnFK = document.getElementById('btn-fk');
const btnIK = document.getElementById('btn-ik');
const btnRecord = document.getElementById('btn-record');
const btnReplay = document.getElementById('btn-replay');
const btnStop = document.getElementById('btn-stop');
const statusIndicator = document.getElementById('status-indicator');
const output = document.getElementById('output');

let isConnected = false;

// Logging
function log(message, type = 'info') {
    console.log(`[${type}] ${message}`);
    const line = document.createElement('div');
    line.className = 'output-line';
    const timestamp = new Date().toLocaleTimeString();
    const icon = type === 'success' ? '✓' : type === 'error' ? '✗' : 'ℹ';
    line.textContent = `[${timestamp}] ${icon} ${message}`;
    output.appendChild(line);
    output.scrollTop = output.scrollHeight;
}

// Initialize WASM
try {
    console.log('Initializing WASM...');
    await init();
    log('WASM module loaded successfully', 'success');
    console.log('connect function:', typeof connect);
} catch (err) {
    console.error('WASM init error:', err);
    log(`Failed to load WASM module: ${err.message}`, 'error');
    log('Make sure you run from a local server: python3 -m http.server 8080', 'error');
}

// Connection
btnConnect.addEventListener('click', async () => {
    console.log('Connect button clicked');
    try {
        btnConnect.disabled = true;
        btnConnect.textContent = 'Connecting...';

        log('Attempting to connect to Reachy Mini...');

        console.log('Calling connect()...');
        const result = await connect(null);
        console.log('Connect result:', result);

        isConnected = true;
        statusIndicator.textContent = 'Connected';
        statusIndicator.className = 'status status-connected';
        btnConnect.textContent = 'Connected';

        // Enable other buttons
        [btnTorqueOn, btnTorqueOff, btnFK, btnIK, btnRecord, btnReplay, btnStop].forEach(btn => {
            btn.disabled = false;
        });

        log('Successfully connected to Reachy Mini!', 'success');
    } catch (err) {
        console.error('Connection error:', err);
        btnConnect.disabled = false;
        btnConnect.textContent = 'Connect to Robot';
        log(`Connection failed: ${err}`, 'error');
    }
});

// Torque Control
btnTorqueOn.addEventListener('click', async () => {
    try {
        log('Enabling torque...');
        await enable_torque();
        log('Torque enabled', 'success');
    } catch (err) {
        log(`Error: ${err}`, 'error');
    }
});

btnTorqueOff.addEventListener('click', async () => {
    try {
        log('Disabling torque...');
        await disable_torque();
        log('Torque disabled', 'success');
    } catch (err) {
        log(`Error: ${err}`, 'error');
    }
});

// Forward Kinematics
btnFK.addEventListener('click', () => {
    try {
        log('Testing forward kinematics...');
        const angles = [0, 0, 0, 0, 0, 0]; // 6 head motors at 0 degrees
        const pose = forward_kinematics(angles);
        log(`Input angles: [${angles.join(', ')}]`);
        log(`Output pose [x, y, z, roll, pitch, yaw]: [${[...pose].map(v => v.toFixed(2)).join(', ')}]`, 'success');
    } catch (err) {
        log(`Error: ${err}`, 'error');
    }
});

// Inverse Kinematics
btnIK.addEventListener('click', () => {
    try {
        log('Testing inverse kinematics...');
        const pose = [0, 0, 0, 0, 0, 0]; // x, y, z, roll, pitch, yaw
        const joints = inverse_kinematics(pose);
        log(`Input pose [x, y, z, roll, pitch, yaw]: [${pose.join(', ')}]`);
        log(`Output joints (degrees): [${[...joints].map(v => v.toFixed(2)).join(', ')}]`, 'success');
    } catch (err) {
        log(`Error: ${err}`, 'error');
    }
});

// Recording
btnRecord.addEventListener('click', async () => {
    try {
        log('Recording movement for 10 seconds...');
        btnRecord.disabled = true;
        await start_fk_stream(10000);  // 10 seconds
        btnRecord.disabled = false;
        log('Recording complete', 'success');
    } catch (err) {
        btnRecord.disabled = false;
        log(`Error: ${err}`, 'error');
    }
});

btnReplay.addEventListener('click', async () => {
    try {
        log('Replaying recorded movement...');
        btnReplay.disabled = true;
        await replay_recording();
        btnReplay.disabled = false;
        log('Replay complete', 'success');
    } catch (err) {
        btnReplay.disabled = false;
        log(`Error: ${err}`, 'error');
    }
});

btnStop.addEventListener('click', async () => {
    try {
        log('Stopping current operation...');
        await stop();
        log('Stopped', 'success');
    } catch (err) {
        log(`Error: ${err.message}`, 'error');
    }
});

log('Ready to connect. Click "Connect to Robot" to begin.');