8bitkick commited on
Commit
98fa906
·
1 Parent(s): d82254a
reachy_mini_app_example/src/RobotManager.js CHANGED
@@ -7,6 +7,10 @@ export class RobotManager {
7
  this.jointMap = {};
8
  this.statusCallback = statusCallback;
9
  this.logged = false;
 
 
 
 
10
 
11
  // URL configuration
12
  this.URDF_URL = new URLSearchParams(location.search).get("urdf")
@@ -65,15 +69,26 @@ export class RobotManager {
65
  this.robot = urdfRobot;
66
  this.robot.rotation.x = -Math.PI / 2; // Rotate 90 degrees around X axis
67
 
68
- // Build joint map
 
69
  this.robot.traverse((child) => {
70
  if (child.isURDFJoint) {
71
  this.jointMap[child.name] = child;
 
 
 
 
 
 
 
72
  }
73
  });
74
 
75
  // Convert robot to blue wireframe after delay
76
- this.applyWireframeMaterial();
 
 
 
77
 
78
  // Clean up the blob URL
79
  URL.revokeObjectURL(blobUrl);
@@ -125,8 +140,41 @@ export class RobotManager {
125
  }
126
 
127
  // Update head pose if available
128
- if (data.head_pose && this.jointMap['yaw_body']) {
129
- if (data.head_pose.yaw !== undefined) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  this.jointMap['yaw_body'].setJointValue(data.head_pose.yaw);
131
  }
132
  }
@@ -150,4 +198,81 @@ export class RobotManager {
150
  getRobot() {
151
  return this.robot;
152
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  }
 
7
  this.jointMap = {};
8
  this.statusCallback = statusCallback;
9
  this.logged = false;
10
+ this.clonedHead = null;
11
+ this.originalHead = null;
12
+ this.baseHeadPosition = new THREE.Vector3();
13
+ this.baseHeadRotation = new THREE.Euler();
14
 
15
  // URL configuration
16
  this.URDF_URL = new URLSearchParams(location.search).get("urdf")
 
69
  this.robot = urdfRobot;
70
  this.robot.rotation.x = -Math.PI / 2; // Rotate 90 degrees around X axis
71
 
72
+ // Build joint map and log robot structure
73
+ console.log('Robot structure:');
74
  this.robot.traverse((child) => {
75
  if (child.isURDFJoint) {
76
  this.jointMap[child.name] = child;
77
+ console.log(` Joint: ${child.name}`, child);
78
+ }
79
+ if (child.isURDFLink) {
80
+ console.log(` Link: ${child.name}`, child);
81
+ }
82
+ if (child.name && (child.name.includes('head') || child.name.includes('frame'))) {
83
+ console.log(` Found head/frame object: ${child.name}`, child);
84
  }
85
  });
86
 
87
  // Convert robot to blue wireframe after delay
88
+ //this.applyWireframeMaterial();
89
+
90
+ // Clone head after robot is fully loaded
91
+ this.cloneHeadForPoseControl();
92
 
93
  // Clean up the blob URL
94
  URL.revokeObjectURL(blobUrl);
 
140
  }
141
 
142
  // Update head pose if available
143
+ if (data.head_pose) {
144
+ // Apply head pose transformations to the cloned head (if it exists)
145
+ if (this.clonedHead) {
146
+ // Apply transformations directly to the cloned head
147
+ // Apply pose relative to the base head position
148
+ if (data.head_pose.x !== undefined) {
149
+ const newX = this.baseHeadPosition.x + data.head_pose.x - 0.01;
150
+ this.clonedHead.position.x = newX;
151
+ }
152
+ if (data.head_pose.y !== undefined) {
153
+ const newY = this.baseHeadPosition.y + data.head_pose.y;
154
+ this.clonedHead.position.y = newY;
155
+ }
156
+ if (data.head_pose.z !== undefined) {
157
+ const newZ = this.baseHeadPosition.z + data.head_pose.z + 0.03;
158
+ this.clonedHead.position.z = newZ;
159
+ }
160
+
161
+ // Apply rotations relative to base rotation
162
+ if (data.head_pose.roll !== undefined) {
163
+ const newRoll = this.baseHeadRotation.x - data.head_pose.pitch;
164
+ this.clonedHead.rotation.x = newRoll;
165
+ }
166
+ if (data.head_pose.pitch !== undefined) {
167
+ const newPitch = this.baseHeadRotation.y - data.head_pose.yaw;
168
+ this.clonedHead.rotation.y = newPitch;
169
+ }
170
+ if (data.head_pose.yaw !== undefined) {
171
+ const newYaw = this.baseHeadRotation.z - data.head_pose.roll;
172
+ this.clonedHead.rotation.z = newYaw;
173
+ }
174
+ }
175
+
176
+ // Also update body yaw joint if it exists (for overall body orientation)
177
+ if (data.head_pose.yaw !== undefined && this.jointMap['yaw_body']) {
178
  this.jointMap['yaw_body'].setJointValue(data.head_pose.yaw);
179
  }
180
  }
 
198
  getRobot() {
199
  return this.robot;
200
  }
201
+
202
+ cloneHeadForPoseControl() {
203
+ // Wait a bit for all STL meshes to finish loading
204
+ setTimeout(() => {
205
+ this.robot.traverse((child) => {
206
+ if ((child.name === 'xl_330')) {
207
+ this.originalHead = child;
208
+
209
+ // Clone the head link for independent control
210
+ this.clonedHead = child.clone();
211
+ this.clonedHead.name = 'cloned_head';
212
+
213
+ // Position the cloned head at the original head's position relative to the robot
214
+ const worldPosition = new THREE.Vector3();
215
+ const worldRotation = new THREE.Quaternion();
216
+ const worldScale = new THREE.Vector3();
217
+ child.matrixWorld.decompose(worldPosition, worldRotation, worldScale);
218
+
219
+ // Convert world position to robot local coordinates
220
+ const robotInverseMatrix = new THREE.Matrix4().copy(this.robot.matrixWorld).invert();
221
+ const localPosition = worldPosition.clone().applyMatrix4(robotInverseMatrix);
222
+
223
+ // Set position relative to robot, not world
224
+ this.clonedHead.position.copy(localPosition);
225
+
226
+ // For rotation, we need to account for the robot's rotation
227
+ const robotRotation = new THREE.Quaternion().setFromEuler(this.robot.rotation);
228
+ const localRotation = worldRotation.clone().premultiply(robotRotation.invert());
229
+ this.clonedHead.quaternion.copy(localRotation);
230
+ this.clonedHead.scale.copy(worldScale);
231
+
232
+ // Store the base position and rotation for relative pose control (in local robot coordinates)
233
+ this.baseHeadPosition.copy(localPosition);
234
+ this.baseHeadRotation.setFromQuaternion(localRotation);
235
+
236
+ // Hide the original head and add the cloned head to the scene
237
+ child.visible = false;
238
+ this.robot.add(this.clonedHead);
239
+
240
+ return; // Exit traverse after finding the head
241
+ }
242
+ });
243
+ }, 3000); // Wait 3 seconds for STL meshes to load
244
+ }
245
+
246
+ debugHeadMovement() {
247
+ // Removed debug movement tracking for cleaner performance
248
+ }
249
+
250
+ stopDebugHeadMovement() {
251
+ // Removed debug movement tracking for cleaner performance
252
+ }
253
+
254
+ // Debug function to manually test head positioning
255
+ testHeadMovement(x = 0, y = 0, z = 0, roll = 0, pitch = 0, yaw = 0) {
256
+ if (!this.clonedHead) {
257
+ console.warn('❌ Cloned head not available for testing');
258
+ return;
259
+ }
260
+
261
+ // Simulate head pose data
262
+ const testData = {
263
+ head_pose: { x, y, z, roll, pitch, yaw }
264
+ };
265
+
266
+ this.updateJoints(testData);
267
+ }
268
+
269
+ // Reset head to base position
270
+ resetHeadPosition() {
271
+ if (!this.clonedHead) {
272
+ return;
273
+ }
274
+
275
+ this.clonedHead.position.copy(this.baseHeadPosition);
276
+ this.clonedHead.rotation.setFromEuler(this.baseHeadRotation);
277
+ }
278
  }