Skip to content

Commit 47d0b0b

Browse files
committed
Address comments
1 parent d75c568 commit 47d0b0b

File tree

4 files changed

+108
-23
lines changed

4 files changed

+108
-23
lines changed

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ rclnodejs.init().then(() => {
3131
- [Installation](#installation)
3232
- [rclnodejs-cli](#rclnodejs-cli)
3333
- [API Documentation](#api-documentation)
34+
- [Electron-based Visualization](#electron-based-visualization)
3435
- [Using TypeScript](#using-rclnodejs-with-typescript)
3536
- [ROS2 Interface Message Generation](#ros2-interface-message-generation-important)
3637
- [Examples](https://github.com/RobotWebTools/rclnodejs/tree/develop/example)
37-
- [Electron Demo](https://github.com/RobotWebTools/rclnodejs/tree/develop/electron_demo)
3838
- [TypeScript Demo](https://github.com/RobotWebTools/rclnodejs/tree/develop/ts_demo)
3939
- [Efficient Usage Tips](./docs/EFFICIENCY.md)
4040
- [FAQ and Known Issues](./docs/FAQ.md)
@@ -96,6 +96,12 @@ Commands:
9696

9797
API documentation is generated by `jsdoc` and can be viewed in the `docs/` folder or [online doc](https://robotwebtools.github.io/rclnodejs/docs/index.html). To create a local copy of the documentation run `npm run docs`.
9898

99+
## Electron-based Visualization
100+
101+
rclnodejs enables the creation of rich, interactive desktop visualization applications using Electron and modern web technologies like Three.js. This approach combines the power of ROS 2 with cross-platform GUI capabilities, allowing developers to build sophisticated 3D visualizations, real-time monitoring dashboards, and interactive control interfaces that can run natively on Windows, macOS, and Linux.
102+
103+
To see this in action, try the `electron_demo/turtle_tf2` demo which demonstrates real-time coordinate frame visualization with dynamic transform broadcasting, interactive 3D navigation, and keyboard-controlled turtle movement - providing a hands-on way to understand ROS 2 TF2 concepts through visual feedback. You can find more Electron-based examples and demos in the [electron_demo](https://github.com/RobotWebTools/rclnodejs/tree/develop/electron_demo) directory.
104+
99105
## Using rclnodejs with TypeScript
100106

101107
`rclnodejs` API can be used in TypeScript projects. You can find the TypeScript declaration files (\*.d.ts) in the `types/` folder.

electron_demo/turtle_tf2/README.md

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,15 @@ npm start
141141
```
142142

143143
4. **Use the web interface to**:
144+
- Click "Start Demo" to initialize all TF2 broadcasters
145+
- Click "Spawn Turtle1" to create turtle1 (required for dynamic frame)
144146
- Click "Spawn Turtle2" to create the second turtle
145147
- Use WASD keys to control turtle1 movement
146148
- Watch turtle2 automatically follow turtle1
147-
- Click "Start Demo" to initialize all TF2 broadcasters
148149
- Use frame toggle buttons to show/hide specific transforms
149150

151+
**⚠️ Important**: The dynamic frame (`carrot1_dynamic`) is only visible when turtle1 exists, as it orbits around turtle1's position in a circular pattern. Make sure to spawn turtle1 first before trying to see the dynamic frame.
152+
150153
## Demo Components
151154

152155
### Main Process (main.js)
@@ -255,9 +258,16 @@ You can observe the following behavior by:
255258

256259
### Frame Visibility
257260

258-
- **Toggle Static**: Show/hide carrot1_static frame
259-
- **Toggle Dynamic**: Show/hide carrot1_dynamic frame
260-
- **Toggle Fixed**: Show/hide carrot1_fixed frame
261+
- **Toggle Static**: Show/hide carrot1_static frame (red sphere, fixed position)
262+
- **Toggle Dynamic**: Show/hide carrot1_dynamic frame (orange sphere, orbits around turtle1)
263+
- **Toggle Fixed**: Show/hide carrot1_fixed frame (purple sphere, fixed offset from turtle1)
264+
265+
**Visual Guide**:
266+
267+
- **Static Frame**: Red sphere at fixed world coordinates (2.0, 3.0, 0.0)
268+
- **Dynamic Frame**: Orange sphere that moves in a circular pattern around the static frame (2-unit radius)
269+
- **Fixed Frame**: Purple sphere that maintains a constant offset relative to turtle1
270+
- **Turtle Frames**: Coordinate axes (X=red, Y=green, Z=blue) attached to each turtle
261271

262272
### 3D Navigation
263273

@@ -288,25 +298,33 @@ You can observe the following behavior by:
288298
- Ensure demo is started: Click "Start Demo" button
289299
- Check TF2 tree: `ros2 run tf2_tools view_frames`
290300

291-
4. **"3D visualization not loading"**
301+
4. **"Dynamic frame not visible when toggling"**
302+
303+
- **Check if the demo is started**: Click "Start Demo" button first to initialize all broadcasters
304+
- **Look for an orange sphere near coordinates (2,3)**: The dynamic frame appears as an orange sphere orbiting around the red static frame
305+
- **Wait for circular motion**: The dynamic frame moves in a 2-unit radius circle, taking about 6 seconds for a full rotation
306+
- **The orange sphere is now bigger**: The dynamic frame has been made 3x larger for better visibility
307+
- **Check the transform list**: The dynamic frame should appear in the left panel's transform list with changing coordinates around (2±2, 3±2, 0)
308+
309+
5. **"3D visualization not loading"**
292310

293311
- Check browser console for WebGL errors
294312
- Ensure hardware acceleration is enabled
295313
- Try restarting the Electron application
296314

297-
5. **"electron: not found" or native module errors**
315+
6. **"electron: not found" or native module errors**
298316

299317
- Make sure you ran `npm run rebuild` after `npm install`
300318
- Ensure Node.js version is compatible (16 or higher)
301319
- Try deleting `node_modules` and running `npm install && npm run rebuild` again
302320

303-
6. **"THREE is not defined" or script loading errors**
321+
7. **"THREE is not defined" or script loading errors**
304322

305323
- Ensure Three.js is properly installed: `npm install [email protected]`
306324
- Check that `node_modules/three/build/three.min.js` exists
307325
- If issues persist, try reinstalling: `rm -rf node_modules && npm install && npm run rebuild`
308326

309-
7. **WSL (Windows Subsystem for Linux) specific issues**
327+
8. **WSL (Windows Subsystem for Linux) specific issues**
310328
- Install audio libraries: `sudo apt install libasound2t64 libasound2-dev`
311329
- Enable X11 forwarding for GUI: Install VcXsrv or similar X server
312330
- Some GUI features may be limited in WSL environment

electron_demo/turtle_tf2/main.js

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -444,19 +444,28 @@ async function createDynamicFrameTf2Broadcaster() {
444444
// Timer to broadcast dynamic transform
445445
const timer = node.createTimer(100, () => {
446446
const now = node.now();
447-
const seconds = now.sec + now.nanosec / 1e9;
448-
const x = seconds * Math.PI;
447+
448+
// Use a more stable time calculation to avoid NaN
449+
const timeInSeconds = Date.now() / 1000.0; // Use JavaScript Date for stable timing
450+
const angle = timeInSeconds * 0.5; // Slower rotation (0.5 rad/sec instead of π rad/sec)
451+
452+
console.log(
453+
'🕒 Dynamic frame time:',
454+
timeInSeconds.toFixed(2),
455+
'angle:',
456+
angle.toFixed(2)
457+
);
449458

450459
const dynamicTransform = {
451460
header: {
452461
stamp: now,
453-
frame_id: 'turtle1',
462+
frame_id: 'carrot1_static',
454463
},
455464
child_frame_id: 'carrot1_dynamic',
456465
transform: {
457466
translation: {
458-
x: 2.0 * Math.sin(x),
459-
y: 2.0 * Math.cos(x),
467+
x: 2.0 * Math.sin(angle),
468+
y: 2.0 * Math.cos(angle),
460469
z: 0.0,
461470
},
462471
rotation: {
@@ -482,13 +491,13 @@ async function createDynamicFrameTf2Broadcaster() {
482491
sec: now.sec,
483492
nanosec: now.nanosec,
484493
},
485-
frame_id: 'turtle1',
494+
frame_id: 'carrot1_static',
486495
},
487496
child_frame_id: 'carrot1_dynamic',
488497
transform: {
489498
translation: {
490-
x: 2.0 * Math.sin(x),
491-
y: 2.0 * Math.cos(x),
499+
x: 2.0 * Math.sin(angle),
500+
y: 2.0 * Math.cos(angle),
492501
z: 0.0,
493502
},
494503
rotation: {
@@ -499,6 +508,15 @@ async function createDynamicFrameTf2Broadcaster() {
499508
},
500509
},
501510
};
511+
512+
console.log(
513+
'📤 Sending dynamic transform:',
514+
'x:',
515+
(2.0 * Math.sin(angle)).toFixed(2),
516+
'y:',
517+
(2.0 * Math.cos(angle)).toFixed(2)
518+
);
519+
502520
mainWindow.webContents.send(
503521
'dynamic-transform-update',
504522
serializableDynamicTransform

electron_demo/turtle_tf2/renderer.js

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ function initializeScene() {
8484
controls.maxDistance = 50;
8585
controls.minDistance = 5;
8686

87+
// Reduce rotation sensitivity for better control
88+
controls.rotateSpeed = 0.3; // Default is 1.0, lower = less sensitive
89+
controls.panSpeed = 0.5; // Reduce pan sensitivity too
90+
controls.zoomSpeed = 0.8; // Slightly reduce zoom sensitivity
91+
8792
// Lighting
8893
const ambientLight = new THREE.AmbientLight(0x404040, 0.6);
8994
scene.add(ambientLight);
@@ -311,15 +316,35 @@ function updateFrame(name, transform) {
311316
if (!frames[name]) {
312317
// Determine color based on frame name
313318
let color = 0xffffff;
314-
if (name.includes('static')) color = 0xff4444;
315-
else if (name.includes('dynamic')) color = 0xffaa00;
316-
else if (name.includes('fixed')) color = 0xaa44ff;
319+
let scale = 0.5; // Default scale
320+
321+
if (name.includes('static')) {
322+
color = 0xff4444;
323+
scale = 1.0; // Bigger for static frame
324+
} else if (name.includes('dynamic')) {
325+
color = 0xff6600; // Bright orange color
326+
scale = 3.0; // MUCH bigger for dynamic frame - very easy to see!
327+
console.log('🟠 Creating DYNAMIC FRAME at:', position);
328+
} else if (name.includes('fixed')) {
329+
color = 0xaa44ff;
330+
scale = 1.2; // Bigger for fixed frame
331+
}
317332

318-
createFrame(name, position, rotation, color);
333+
createFrame(name, position, rotation, color, scale);
319334
} else {
320335
// Update existing frame
321336
frames[name].position.set(position.x, position.y, position.z);
322337

338+
// Log dynamic frame updates
339+
if (name.includes('dynamic')) {
340+
console.log(
341+
'🟠 Dynamic frame updated at:',
342+
position.x.toFixed(2),
343+
position.y.toFixed(2),
344+
position.z.toFixed(2)
345+
);
346+
}
347+
323348
const euler = new THREE.Euler().setFromQuaternion(
324349
new THREE.Quaternion(rotation.x, rotation.y, rotation.z, rotation.w)
325350
);
@@ -372,6 +397,13 @@ function setupEventListeners() {
372397
});
373398

374399
document.getElementById('toggle-dynamic').addEventListener('click', () => {
400+
console.log('🔄 Dynamic Frame button clicked!');
401+
console.log(
402+
'🔍 Current dynamic frame visible:',
403+
frames['carrot1_dynamic']
404+
? frames['carrot1_dynamic'].visible
405+
: 'not created yet'
406+
);
375407
toggleFrameVisibility('carrot1_dynamic');
376408
});
377409

@@ -413,8 +445,8 @@ function setupKeyboardControls() {
413445
function sendTurtleCommand() {
414446
let linear_x = 0;
415447
let angular_z = 0;
416-
const speed = 2.0; // Linear speed
417-
const turn_speed = 2.0; // Angular speed
448+
const speed = 0.8; // Linear speed - reduced from 2.0 for better control
449+
const turn_speed = 0.6; // Angular speed - further reduced from 1.2 for precise rotation control
418450

419451
// Check for forward/backward movement (W/S keys only)
420452
if (keyState.w) {
@@ -651,8 +683,19 @@ function resetDemo() {
651683
}
652684

653685
function toggleFrameVisibility(frameName) {
686+
console.log('🎯 Toggling frame:', frameName);
654687
if (frames[frameName]) {
655688
frames[frameName].visible = !frames[frameName].visible;
689+
console.log(
690+
'✅ Frame',
691+
frameName,
692+
'is now',
693+
frames[frameName].visible ? 'VISIBLE' : 'HIDDEN'
694+
);
695+
console.log('📍 Frame position:', frames[frameName].position);
696+
} else {
697+
console.log('❌ Frame', frameName, 'does not exist yet!');
698+
console.log('📋 Available frames:', Object.keys(frames));
656699
}
657700
}
658701

0 commit comments

Comments
 (0)