Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/linux-arm64-build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ jobs:
- name: Install test-msgs on Linux
run: |
sudo apt install ros-${{ matrix.ros_distribution }}-test-msgs
# Adjust dependencies based on Ubuntu version
LIBASOUND_PKG="libasound2"
if grep -q "24.04" /etc/os-release; then
LIBASOUND_PKG="libasound2t64"
fi
sudo apt install -y xvfb libgtk-3-0 libnss3 $LIBASOUND_PKG libgbm-dev
- uses: actions/checkout@v6

Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/linux-x64-build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ jobs:
- name: Install test-msgs on Linux
run: |
sudo apt install ros-${{ matrix.ros_distribution }}-test-msgs
# Adjust dependencies based on Ubuntu version
LIBASOUND_PKG="libasound2"
if grep -q "24.04" /etc/os-release; then
LIBASOUND_PKG="libasound2t64"
fi
sudo apt install -y xvfb libgtk-3-0 libnss3 $LIBASOUND_PKG libgbm-dev
- uses: actions/checkout@v6

Expand Down
2 changes: 1 addition & 1 deletion electron_demo/car/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@
},
"devDependencies": {
"@electron/rebuild": "^3.6.0",
"electron": "^31.0.0"
"electron": "^40.0.0"
}
}
8 changes: 8 additions & 0 deletions electron_demo/car/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// limitations under the License.

const { ipcRenderer } = require('electron');
const process = require('process');

// DOM elements
let currentCommandEl, linearXEl, angularZEl, topicNameEl;
Expand All @@ -27,6 +28,13 @@ document.addEventListener('DOMContentLoaded', function () {
initializeElements();
setupEventListeners();
setupROSListeners();

const versionDiv = document.createElement('div');
versionDiv.style.textAlign = 'center';
versionDiv.style.padding = '10px';
versionDiv.style.marginTop = '20px';
versionDiv.innerText = 'Electron version: ' + process.versions.electron;
document.querySelector('.container').appendChild(versionDiv);
});

function initializeElements() {
Expand Down
5 changes: 5 additions & 0 deletions electron_demo/manipulator/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ <h4>Two-Joint Manipulator Demo</h4>
<li><strong>JointState</strong> - ROS2 sensor_msgs</li>
</ul>
<p>Use the sliders to control joint angles or start automatic animation.</p>
<p>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>.
</p>
<hr>
<h5>🎯 What to Look For:</h5>
<ul>
Expand Down
2 changes: 1 addition & 1 deletion electron_demo/manipulator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@
},
"devDependencies": {
"@electron/rebuild": "^3.7.2",
"electron": "^31.7.7"
"electron": "^40.0.0"
}
}
20 changes: 20 additions & 0 deletions electron_demo/manipulator/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// limitations under the License.

const { ipcRenderer } = require('electron');
const process = require('process');

// Three.js scene components
let scene, camera, renderer, controls;
Expand All @@ -28,6 +29,16 @@ let jointAngles = {

// Initialize the 3D scene
function initScene() {
const versionDiv = document.createElement('div');
versionDiv.style.position = 'absolute';
versionDiv.style.bottom = '10px';
versionDiv.style.right = '10px';
versionDiv.style.color = 'white';
versionDiv.style.fontFamily = 'Arial, sans-serif';
versionDiv.style.zIndex = '1000';
versionDiv.innerText = 'Electron version: ' + process.versions.electron;
document.body.appendChild(versionDiv);

const container = document.getElementById('canvas-container');

// Scene setup
Expand Down Expand Up @@ -358,6 +369,15 @@ window.addEventListener('resize', () => {

// UI event handlers
document.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector);
if (element) element.innerText = text;
};

for (const type of ['chrome', 'node', 'electron']) {
replaceText(`${type}-version`, process.versions[type] || 'Unavailable');
}

initScene();
setupUIEventHandlers();
startFrequencyMeasurement();
Expand Down
2 changes: 1 addition & 1 deletion electron_demo/topics/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
},
"devDependencies": {
"@electron/rebuild": "^3.6.0",
"electron": "^31.0.0"
"electron": "^40.0.0"
}
}
10 changes: 10 additions & 0 deletions electron_demo/topics/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@
// limitations under the License.

const { ipcRenderer } = require('electron');
const process = require('process');

document.addEventListener('DOMContentLoaded', () => {
const versionDiv = document.createElement('div');
versionDiv.style.position = 'fixed';
versionDiv.style.bottom = '10px';
versionDiv.style.left = '10px';
versionDiv.innerText = 'Electron version: ' + process.versions.electron;
document.body.appendChild(versionDiv);
});

ipcRenderer.on('topic-received', function (event, response) {
document.getElementById('received-topic').innerText = response;
Expand Down
6 changes: 3 additions & 3 deletions electron_demo/turtle_tf2/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ async function createTurtleTf2Listener() {
);

// Timer to check for transforms and control turtle2
const timer = node.createTimer(1000, () => {
node.createTimer(1000n, () => {
// Wrap the async logic in a try-catch to handle promise rejections
(async () => {
try {
Expand Down Expand Up @@ -442,7 +442,7 @@ async function createDynamicFrameTf2Broadcaster() {
const tfBroadcaster = node.createPublisher('tf2_msgs/msg/TFMessage', '/tf');

// Timer to broadcast dynamic transform
const timer = node.createTimer(100, () => {
node.createTimer(100n, () => {
const now = node.now();

// Use a more stable time calculation to avoid NaN
Expand Down Expand Up @@ -535,7 +535,7 @@ async function createFixedFrameTf2Broadcaster() {
const tfBroadcaster = node.createPublisher('tf2_msgs/msg/TFMessage', '/tf');

// Timer to broadcast fixed transform
const timer = node.createTimer(100, () => {
node.createTimer(100n, () => {
const now = node.now();
const fixedTransform = {
header: {
Expand Down
2 changes: 1 addition & 1 deletion electron_demo/turtle_tf2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@
},
"devDependencies": {
"@electron/rebuild": "^3.7.2",
"electron": "^31.7.7"
"electron": "^40.0.0"
}
}
15 changes: 15 additions & 0 deletions electron_demo/turtle_tf2/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// limitations under the License.

const { ipcRenderer } = require('electron');
const process = require('process');

// 3D Scene variables
let scene, camera, renderer, controls;
Expand Down Expand Up @@ -41,10 +42,24 @@ let keyState = {

// Initialize when DOM is loaded
document.addEventListener('DOMContentLoaded', function () {
// Display Electron Version
const versionDiv = document.createElement('div');
versionDiv.style.position = 'fixed';
versionDiv.style.top = '25px';
versionDiv.style.right = '20px';
versionDiv.style.color = 'rgba(255, 255, 255, 0.9)';
versionDiv.style.fontSize = '14px';
versionDiv.style.fontWeight = 'bold';
versionDiv.style.zIndex = '999999';
versionDiv.style.pointerEvents = 'none';
versionDiv.innerText = 'Electron: ' + process.versions.electron;
document.body.appendChild(versionDiv);

initializeScene();
setupEventListeners();
setupKeyboardControls();
setupROSListeners();

updateStatus();

// Don't automatically hide loading screen - wait for ROS2 initialization
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"install": "node scripts/install.js",
"postinstall": "npm run generate-messages",
"docs": "cd docs && make",
"test": "nyc node --expose-gc ./scripts/run_test.js && tsd",
"test": "nyc node --expose-gc ./scripts/run_test.js && tsd && npm install --no-save electron && node test/electron/run_test.js",
"test-idl": "nyc node --expose-gc ./scripts/run_test.js --idl",
"lint": "eslint && node ./scripts/cpplint.js",
"format": "clang-format -i -style=file ./src/*.cpp ./src/*.h && npx --yes prettier --write \"{lib,rosidl_gen,rostsd_gen,rosidl_parser,types,example,test,scripts,benchmark,rostsd_gen}/**/*.{js,md,ts}\" ./*.{js,md,ts}",
Expand Down
47 changes: 47 additions & 0 deletions test/electron/run_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use strict';

const path = require('path');
const { spawn } = require('child_process');

let electron;
try {
electron = require('electron');
} catch (e) {
console.error(
'Electron module not found. Please install electron to run this test.'
);
process.exit(1);
}

let command = electron;
let args = [path.join(__dirname, 'test_usability.js'), '--no-sandbox'];

// Handle headless Linux environments (like CI) by using xvfb-run
if (process.platform === 'linux' && !process.env.DISPLAY) {
console.log('No DISPLAY detected. Attempting to use xvfb-run...');
command = 'xvfb-run';
// -a: --auto-servernum (use explicit server number to avoid conflicts)
args = ['-a', electron, ...args];
}

console.log('Launching Electron to run test_usability.js...');
const child = spawn(command, args, {
stdio: 'inherit',
env: { ...process.env, ELECTRON_ENABLE_LOGGING: true },
});

child.on('close', (code) => {
console.log(`Electron process exited with code ${code}`);
if (code === 0) {
console.log('Test Passed!');
process.exit(0);
} else {
console.error('Test Failed!');
process.exit(1);
}
});

child.on('error', (err) => {
console.error('Failed to start electron:', err);
process.exit(1);
});
57 changes: 57 additions & 0 deletions test/electron/test_usability.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
'use strict';

const rclnodejs = require('../../index.js');
const { app } = require('electron');

app.on('ready', () => {
console.log('Electron version:', process.versions.electron);
rclnodejs
.init()
.then(() => {
console.log('rclnodejs initialized successfully.');
const node = rclnodejs.createNode('test_electron_node');
const publisher = node.createPublisher(
'std_msgs/msg/String',
'electron_test_topic'
);

const subscription = node.createSubscription(
'std_msgs/msg/String',
'electron_test_topic',
(msg) => {
if (msg.data === 'Hello from Electron') {
console.log(
'Successfully received message in Electron environment.'
);
rclnodejs.shutdown();
app.quit();
process.exit(0);
}
}
);

console.log('Publisher and Subscriber created.');

// Publish repeatedly until received
const interval = setInterval(() => {
publisher.publish('Hello from Electron');
console.log('Published message...');
}, 100);

// Set a timeout to fail the test
setTimeout(() => {
console.error('Test Failed: Timeout waiting for message.');
clearInterval(interval);
rclnodejs.shutdown();
app.quit();
process.exit(1);
}, 10000);

rclnodejs.spin(node);
})
.catch((e) => {
console.error('Initialization failed:', e);
app.quit();
process.exit(1);
});
});
Loading