diff --git a/.npmignore b/.npmignore index 947bfcd51..d24e04c8f 100644 --- a/.npmignore +++ b/.npmignore @@ -26,6 +26,7 @@ tutorials/ electron_demo/ ts_demo/ tools/ +demo/ .github/ .nyc_output/ .vscode/ diff --git a/README.md b/README.md index 6dc9f07ad..8735f0621 100644 --- a/README.md +++ b/README.md @@ -144,10 +144,10 @@ Create rich, interactive desktop applications using Electron and web technologie | Demo | Description | Screenshot | | :-----------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------: | -| **🐢 [turtle_tf2](./electron_demo/turtle_tf2)** | Real-time coordinate frame visualization with turtle control. Features TF2 transforms, keyboard control, and dynamic frame updates. | ![turtle_tf2](./electron_demo/turtle_tf2/turtle-tf2-demo.png) | -| **🦾 [manipulator](./electron_demo/manipulator)** | Interactive two-joint robotic arm simulation. Features 3D joint visualization, manual/automatic control, and visual movement markers. | ![manipulator](./electron_demo/manipulator/manipulator-demo.png) | +| **🐢 [turtle_tf2](./demo/electron/turtle_tf2)** | Real-time coordinate frame visualization with turtle control. Features TF2 transforms, keyboard control, and dynamic frame updates. | ![turtle_tf2](./demo/electron/turtle_tf2/turtle-tf2-demo.png) | +| **🦾 [manipulator](./demo/electron/manipulator)** | Interactive two-joint robotic arm simulation. Features 3D joint visualization, manual/automatic control, and visual movement markers. | ![manipulator](./demo/electron/manipulator/manipulator-demo.png) | -Explore more examples in [electron_demo](https://github.com/RobotWebTools/rclnodejs/tree/develop/electron_demo). +Explore more examples in [demo/electron](https://github.com/RobotWebTools/rclnodejs/tree/develop/demo/electron). ## Using rclnodejs with TypeScript @@ -175,7 +175,7 @@ rclnodejs.init().then(() => { }); ``` -See [TypeScript demos](https://github.com/RobotWebTools/rclnodejs/tree/develop/ts_demo) for more examples. +See [TypeScript demos](https://github.com/RobotWebTools/rclnodejs/tree/develop/demo/typescript) for more examples. ## Observable Subscriptions diff --git a/electron_demo/README.md b/demo/electron/README.md similarity index 100% rename from electron_demo/README.md rename to demo/electron/README.md diff --git a/electron_demo/car/README.md b/demo/electron/car/README.md similarity index 100% rename from electron_demo/car/README.md rename to demo/electron/car/README.md diff --git a/electron_demo/car/car-control-electron.gif b/demo/electron/car/car-control-electron.gif similarity index 100% rename from electron_demo/car/car-control-electron.gif rename to demo/electron/car/car-control-electron.gif diff --git a/electron_demo/car/index.html b/demo/electron/car/index.html similarity index 100% rename from electron_demo/car/index.html rename to demo/electron/car/index.html diff --git a/electron_demo/car/main.js b/demo/electron/car/main.js similarity index 100% rename from electron_demo/car/main.js rename to demo/electron/car/main.js diff --git a/electron_demo/car/package.json b/demo/electron/car/package.json similarity index 100% rename from electron_demo/car/package.json rename to demo/electron/car/package.json diff --git a/electron_demo/car/renderer.js b/demo/electron/car/renderer.js similarity index 100% rename from electron_demo/car/renderer.js rename to demo/electron/car/renderer.js diff --git a/electron_demo/manipulator/README.md b/demo/electron/manipulator/README.md similarity index 99% rename from electron_demo/manipulator/README.md rename to demo/electron/manipulator/README.md index 76c3497d5..616769367 100644 --- a/electron_demo/manipulator/README.md +++ b/demo/electron/manipulator/README.md @@ -25,7 +25,7 @@ An interactive Electron application demonstrating a two-joint robotic manipulato 1. **Navigate to the demo directory**: ```bash - cd rclnodejs/electron_demo/manipulator + cd rclnodejs/demo/electron/manipulator ``` 2. **Install dependencies**: diff --git a/electron_demo/manipulator/index.html b/demo/electron/manipulator/index.html similarity index 100% rename from electron_demo/manipulator/index.html rename to demo/electron/manipulator/index.html diff --git a/electron_demo/manipulator/main.js b/demo/electron/manipulator/main.js similarity index 100% rename from electron_demo/manipulator/main.js rename to demo/electron/manipulator/main.js diff --git a/electron_demo/manipulator/manipulator-demo.gif b/demo/electron/manipulator/manipulator-demo.gif similarity index 100% rename from electron_demo/manipulator/manipulator-demo.gif rename to demo/electron/manipulator/manipulator-demo.gif diff --git a/electron_demo/manipulator/manipulator-demo.png b/demo/electron/manipulator/manipulator-demo.png similarity index 100% rename from electron_demo/manipulator/manipulator-demo.png rename to demo/electron/manipulator/manipulator-demo.png diff --git a/electron_demo/manipulator/package.json b/demo/electron/manipulator/package.json similarity index 100% rename from electron_demo/manipulator/package.json rename to demo/electron/manipulator/package.json diff --git a/electron_demo/manipulator/renderer.js b/demo/electron/manipulator/renderer.js similarity index 100% rename from electron_demo/manipulator/renderer.js rename to demo/electron/manipulator/renderer.js diff --git a/electron_demo/topics/README.md b/demo/electron/topics/README.md similarity index 99% rename from electron_demo/topics/README.md rename to demo/electron/topics/README.md index e06a3a03b..20f2f504e 100644 --- a/electron_demo/topics/README.md +++ b/demo/electron/topics/README.md @@ -30,7 +30,7 @@ A minimal Electron application demonstrating basic ROS2 topic communication usin 1. **Navigate to the demo directory**: ```bash - cd rclnodejs/electron_demo/topics + cd rclnodejs/demo/electron/topics ``` 2. **Source your ROS 2 environment**: diff --git a/electron_demo/topics/electron-demo.gif b/demo/electron/topics/electron-demo.gif similarity index 100% rename from electron_demo/topics/electron-demo.gif rename to demo/electron/topics/electron-demo.gif diff --git a/electron_demo/topics/index.html b/demo/electron/topics/index.html similarity index 100% rename from electron_demo/topics/index.html rename to demo/electron/topics/index.html diff --git a/electron_demo/topics/main.js b/demo/electron/topics/main.js similarity index 100% rename from electron_demo/topics/main.js rename to demo/electron/topics/main.js diff --git a/electron_demo/topics/package.json b/demo/electron/topics/package.json similarity index 100% rename from electron_demo/topics/package.json rename to demo/electron/topics/package.json diff --git a/electron_demo/topics/renderer.js b/demo/electron/topics/renderer.js similarity index 100% rename from electron_demo/topics/renderer.js rename to demo/electron/topics/renderer.js diff --git a/electron_demo/turtle_tf2/README.md b/demo/electron/turtle_tf2/README.md similarity index 99% rename from electron_demo/turtle_tf2/README.md rename to demo/electron/turtle_tf2/README.md index 89ad595ed..33ae9a002 100644 --- a/electron_demo/turtle_tf2/README.md +++ b/demo/electron/turtle_tf2/README.md @@ -77,7 +77,7 @@ The demo uses the following key dependencies: 1. **Navigate to the demo directory**: ```bash - cd electron_demo/turtle_tf2 + cd demo/electron/turtle_tf2 ``` 2. **Install dependencies**: diff --git a/electron_demo/turtle_tf2/index.html b/demo/electron/turtle_tf2/index.html similarity index 100% rename from electron_demo/turtle_tf2/index.html rename to demo/electron/turtle_tf2/index.html diff --git a/electron_demo/turtle_tf2/main.js b/demo/electron/turtle_tf2/main.js similarity index 100% rename from electron_demo/turtle_tf2/main.js rename to demo/electron/turtle_tf2/main.js diff --git a/electron_demo/turtle_tf2/orbit-controls.js b/demo/electron/turtle_tf2/orbit-controls.js similarity index 100% rename from electron_demo/turtle_tf2/orbit-controls.js rename to demo/electron/turtle_tf2/orbit-controls.js diff --git a/electron_demo/turtle_tf2/package.json b/demo/electron/turtle_tf2/package.json similarity index 100% rename from electron_demo/turtle_tf2/package.json rename to demo/electron/turtle_tf2/package.json diff --git a/electron_demo/turtle_tf2/renderer.js b/demo/electron/turtle_tf2/renderer.js similarity index 100% rename from electron_demo/turtle_tf2/renderer.js rename to demo/electron/turtle_tf2/renderer.js diff --git a/electron_demo/turtle_tf2/turtle-tf2-demo.gif b/demo/electron/turtle_tf2/turtle-tf2-demo.gif similarity index 100% rename from electron_demo/turtle_tf2/turtle-tf2-demo.gif rename to demo/electron/turtle_tf2/turtle-tf2-demo.gif diff --git a/electron_demo/turtle_tf2/turtle-tf2-demo.png b/demo/electron/turtle_tf2/turtle-tf2-demo.png similarity index 100% rename from electron_demo/turtle_tf2/turtle-tf2-demo.png rename to demo/electron/turtle_tf2/turtle-tf2-demo.png diff --git a/demo/rosocket/README.md b/demo/rosocket/README.md new file mode 100644 index 000000000..6e35b96ae --- /dev/null +++ b/demo/rosocket/README.md @@ -0,0 +1,93 @@ +# rosocket demo (browser ↔ ROS 2) + +A minimal end-to-end example of the +[`rosocket`](../../rosocket/README.md) WebSocket bridge. The Node +server runs anywhere ROS 2 is sourced; the HTML page runs in any +modern browser and talks to it over plain `WebSocket` — no client +library required. + +## What it shows + +- Subscribe to and publish on `/chatter` (`std_msgs/msg/String`). +- Call `/add_two_ints` (`example_interfaces/srv/AddTwoInts`) — the + service implementation lives in + [`example/services/service/service-example.js`](../../example/services/service/service-example.js) + and is launched in a second terminal. + +## Layout + +- `server.js` — `rclnodejs` node + `startRosocket` bridge only. +- `index.html` — single-file browser client using only built-in + `WebSocket` and `JSON`. + +## Run the bridge + +```bash +# 1. Source your ROS 2 distro (humble / jazzy / kilted / lyrical / rolling) +source /opt/ros/$ROS_DISTRO/setup.bash + +# 2. Terminal A — start the WebSocket bridge +node demo/rosocket/server.js +# [rosocket-demo] listening on ws://localhost:9000 (bind=0.0.0.0) + +# 3. Terminal B — start the AddTwoInts service so the browser has +# something to call +node example/services/service/service-example.js +``` + +The server binds to `0.0.0.0:9000` so it is reachable from any host +that can route to the machine running it. + +## Open the page + +Open `demo/rosocket/index.html` in any modern browser (double-click, +or `File > Open`). Leave the bridge field as `ws://localhost:9000` +when the browser and the bridge run on the same machine, and click +**Subscribe**, then **Publish**, then **Call**. + +If the browser is on a different machine than the bridge (remote ROS +box, container, VM, WSL → host browser, etc.), change the bridge +field to point at the bridge host, e.g. `ws://192.0.2.10:9000` or +`ws://my-ros-host.local:9000`, and reconnect. + +> WSL note: WSL2 normally forwards `localhost` to Windows, so +> `ws://localhost:9000` works as-is. On WSL1 or with custom/mirrored +> networking, use the WSL IP (`hostname -I | awk '{print $1}'`) +> instead. + +### Verify from the ROS 2 side (optional) + +```bash +# Always works (explicit type), even before any browser tab is connected: +ros2 topic echo /chatter std_msgs/msg/String + +# Auto-discovery form — only works after a browser tab is connected to +# ws://.../topic/chatter (the bridge creates the subscription on demand) +# and after a publisher exists on the topic (browser Publish, or the +# `ros2 topic pub` command below): +ros2 topic echo /chatter + +ros2 topic pub /chatter std_msgs/msg/String "{data: 'hi from ros2'}" +ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 7, b: 5}" +``` + +> If you see `WARNING: topic [/chatter] does not appear to be published yet +> / Could not determine the type for the passed topic`, it just means no +> publisher exists on `/chatter` yet — use the explicit-type form above, +> or click **Subscribe** + **Publish** in the browser first. + +Anything you publish from the browser shows up in `ros2 topic echo`, +and any `ros2 topic pub` to `/chatter` shows up in the browser +subscription log. + +## URL scheme reminder + +``` +ws://:/topic/?type=/msg/ +ws://:/service/?type=/srv/ +``` + +This demo pre-declares both types server-side via `topicTypes` / +`serviceTypes`, so the browser can omit `?type=`. See +[`rosocket/README.md`](../../rosocket/README.md) for the full +protocol reference. diff --git a/demo/rosocket/index.html b/demo/rosocket/index.html new file mode 100644 index 000000000..aba379cc4 --- /dev/null +++ b/demo/rosocket/index.html @@ -0,0 +1,220 @@ + + + + + + rosocket demo + + + +

rosocket demo

+

+ Browser ↔ ROS 2 over plain WebSocket. Adjust the bridge URL if your WSL + IP differs from localhost. +

+

+ Bridge: + +

+ +

Topic: /chatter (std_msgs/msg/String)

+
+
+

+ + +

+

+ + +

+
+
+
// Subscribe — every published message arrives as onmessage.
+const sub = new WebSocket('ws://localhost:9000/topic/chatter');
+sub.onmessage = (ev) => console.log('recv:', ev.data);
+// e.g. {"data":"hi"}
+
+// Publish — open, send JSON, close.
+const ws = new WebSocket('ws://localhost:9000/topic/chatter');
+ws.onopen = () => {
+  ws.send(JSON.stringify({ data: 'hello from browser' }));
+  setTimeout(() => ws.close(), 200); // let it flush
+};
+
+ +

Service: /add_two_ints (example_interfaces/srv/AddTwoInts)

+
+
+

+ a: b: + + +

+
+
+
// Service call — send {id, request}, await one response, close.
+const ws = new WebSocket('ws://localhost:9000/service/add_two_ints');
+ws.onopen = () => ws.send(JSON.stringify({
+  id: 1,
+  request: { a: '2n', b: '3n' }, // int64 → "Nn" string
+}));
+ws.onmessage = (ev) => {
+  console.log('resp:', ev.data);
+  // {"id":1,"response":{"sum":"5n"}}
+  ws.close();
+};
+
+ + + + diff --git a/demo/rosocket/server.js b/demo/rosocket/server.js new file mode 100644 index 000000000..5f5898d1f --- /dev/null +++ b/demo/rosocket/server.js @@ -0,0 +1,78 @@ +// Copyright (c) 2026 RobotWebTools Contributors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +'use strict'; + +// rosocket demo server. +// +// Bridges two ROS 2 endpoints to plain WebSocket URLs so a browser can +// drive them with built-in `WebSocket` + `JSON`, no client library: +// +// ws://:9000/topic/chatter std_msgs/msg/String +// ws://:9000/service/add_two_ints example_interfaces/srv/AddTwoInts +// +// Run inside WSL (where ROS 2 is sourced): +// node demo/rosocket/server.js +// +// To exercise the service, start the existing AddTwoInts example in a +// second terminal (it implements `/add_two_ints`): +// node example/services/service/service-example.js +// +// Then open demo/rosocket/index.html on the Windows host browser. WSL2 +// forwards localhost so `ws://localhost:9000` works as-is. See README.md +// for fallback instructions. + +const rclnodejs = require('../../index.js'); +const { startRosocket } = require('../../rosocket'); + +const PORT = Number(process.env.PORT) || 9000; +const HOST = process.env.HOST || '0.0.0.0'; + +async function main() { + await rclnodejs.init(); + const node = rclnodejs.createNode('rosocket_demo_node'); + rclnodejs.spin(node); + + const bridge = await startRosocket({ + node, + port: PORT, + host: HOST, + topicTypes: { + '/chatter': 'std_msgs/msg/String', + }, + serviceTypes: { + '/add_two_ints': 'example_interfaces/srv/AddTwoInts', + }, + }); + + const displayHost = HOST === '0.0.0.0' || HOST === '::' ? 'localhost' : HOST; + const baseUrl = `ws://${displayHost}:${bridge.port}`; + console.log( + `[rosocket-demo] listening on ${baseUrl} (bind=${HOST}:${bridge.port})` + ); + console.log('[rosocket-demo] endpoints:'); + console.log(` ${baseUrl}/topic/chatter`); + console.log(` ${baseUrl}/service/add_two_ints`); + console.log('Open demo/rosocket/index.html in the host browser to try it.'); + + const shutdown = () => { + bridge.close().finally(() => { + try { + rclnodejs.shutdown(); + } catch (_) {} + process.exit(0); + }); + }; + process.on('SIGINT', shutdown); + process.on('SIGTERM', shutdown); +} + +main().catch((e) => { + console.error(e.stack || e.message); + process.exit(1); +}); diff --git a/ts_demo/README.md b/demo/typescript/README.md similarity index 94% rename from ts_demo/README.md rename to demo/typescript/README.md index 9619ade74..3ce710873 100644 --- a/ts_demo/README.md +++ b/demo/typescript/README.md @@ -59,7 +59,7 @@ Asynchronous actions with progress feedback and cancellation ## 🔗 Related Resources -- [rclnodejs Tutorials](../tutorials/) - Comprehensive API documentation -- [Electron Demos](../electron_demo/) - GUI applications with rclnodejs +- [rclnodejs Tutorials](../../tutorials/) - Comprehensive API documentation +- [Electron Demos](../electron/) - GUI applications with rclnodejs - [TypeScript Handbook](https://www.typescriptlang.org/docs/) - Language reference - [ROS2 Documentation](https://docs.ros.org/) - Official ROS2 concepts diff --git a/ts_demo/actions/README.md b/demo/typescript/actions/README.md similarity index 99% rename from ts_demo/actions/README.md rename to demo/typescript/actions/README.md index 015d9f3c9..447e28b94 100644 --- a/ts_demo/actions/README.md +++ b/demo/typescript/actions/README.md @@ -32,7 +32,7 @@ This demo implements a Fibonacci sequence calculator using ROS2 actions: ## Project Structure ``` -ts_demo/actions/ +demo/typescript/actions/ ├── src/ │ ├── client.ts # Action client implementation │ └── server.ts # Action server implementation @@ -74,7 +74,7 @@ Before running this demo, ensure you have: 3. **Navigate to the demo directory**: ```bash - cd ts_demo/actions + cd demo/typescript/actions ``` 4. **Install dependencies**: diff --git a/ts_demo/actions/package.json b/demo/typescript/actions/package.json similarity index 100% rename from ts_demo/actions/package.json rename to demo/typescript/actions/package.json diff --git a/ts_demo/actions/src/client.ts b/demo/typescript/actions/src/client.ts similarity index 100% rename from ts_demo/actions/src/client.ts rename to demo/typescript/actions/src/client.ts diff --git a/ts_demo/actions/src/server.ts b/demo/typescript/actions/src/server.ts similarity index 100% rename from ts_demo/actions/src/server.ts rename to demo/typescript/actions/src/server.ts diff --git a/ts_demo/actions/tsconfig.json b/demo/typescript/actions/tsconfig.json similarity index 100% rename from ts_demo/actions/tsconfig.json rename to demo/typescript/actions/tsconfig.json diff --git a/ts_demo/services/README.md b/demo/typescript/services/README.md similarity index 99% rename from ts_demo/services/README.md rename to demo/typescript/services/README.md index df754bba8..26280c126 100644 --- a/ts_demo/services/README.md +++ b/demo/typescript/services/README.md @@ -48,7 +48,7 @@ npm run build Navigate to this demo directory and install dependencies: ```bash -cd ts_demo/services +cd demo/typescript/services npm install ``` diff --git a/ts_demo/services/package.json b/demo/typescript/services/package.json similarity index 100% rename from ts_demo/services/package.json rename to demo/typescript/services/package.json diff --git a/ts_demo/services/src/client.ts b/demo/typescript/services/src/client.ts similarity index 100% rename from ts_demo/services/src/client.ts rename to demo/typescript/services/src/client.ts diff --git a/ts_demo/services/src/server.ts b/demo/typescript/services/src/server.ts similarity index 100% rename from ts_demo/services/src/server.ts rename to demo/typescript/services/src/server.ts diff --git a/ts_demo/services/tsconfig.json b/demo/typescript/services/tsconfig.json similarity index 100% rename from ts_demo/services/tsconfig.json rename to demo/typescript/services/tsconfig.json diff --git a/ts_demo/topics/README.md b/demo/typescript/topics/README.md similarity index 99% rename from ts_demo/topics/README.md rename to demo/typescript/topics/README.md index ee158beb9..928ec2f98 100644 --- a/ts_demo/topics/README.md +++ b/demo/typescript/topics/README.md @@ -47,7 +47,7 @@ npm run build Navigate to this demo directory and install dependencies: ```bash -cd ts_demo/topics +cd demo/typescript/topics npm install ``` @@ -162,7 +162,7 @@ Starting TypeScript Subscriber Demo... ## Project Structure ``` -ts_demo/topics/ +demo/typescript/topics/ ├── package.json # Project dependencies and scripts ├── tsconfig.json # TypeScript configuration ├── README.md # This file @@ -239,7 +239,7 @@ This demo showcases several TypeScript advantages: **Solution**: Ensure you're in the correct directory and rclnodejs is properly linked: ```bash - cd ts_demo/topics + cd demo/typescript/topics npm install ``` diff --git a/ts_demo/topics/package.json b/demo/typescript/topics/package.json similarity index 100% rename from ts_demo/topics/package.json rename to demo/typescript/topics/package.json diff --git a/ts_demo/topics/src/publisher.ts b/demo/typescript/topics/src/publisher.ts similarity index 100% rename from ts_demo/topics/src/publisher.ts rename to demo/typescript/topics/src/publisher.ts diff --git a/ts_demo/topics/src/subscriber.ts b/demo/typescript/topics/src/subscriber.ts similarity index 100% rename from ts_demo/topics/src/subscriber.ts rename to demo/typescript/topics/src/subscriber.ts diff --git a/ts_demo/topics/tsconfig.json b/demo/typescript/topics/tsconfig.json similarity index 100% rename from ts_demo/topics/tsconfig.json rename to demo/typescript/topics/tsconfig.json diff --git a/eslint.config.mjs b/eslint.config.mjs index a40fdcaab..75f596d21 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -15,7 +15,7 @@ export default [ "**/scripts/", "**/benchmark/", "**/docs/", - "**/electron_demo/", + "**/demo/electron/", ], }, { diff --git a/scripts/npmjs-readme.md b/scripts/npmjs-readme.md index 5d1cca269..73fc37543 100644 --- a/scripts/npmjs-readme.md +++ b/scripts/npmjs-readme.md @@ -68,8 +68,9 @@ npm install rclnodejs - API documentation: [robotwebtools.github.io/rclnodejs/docs](https://robotwebtools.github.io/rclnodejs/docs/index.html) - Tutorials: [tutorials/](https://github.com/RobotWebTools/rclnodejs/tree/develop/tutorials) - JavaScript examples: [example/](https://github.com/RobotWebTools/rclnodejs/tree/develop/example) -- TypeScript demos: [ts_demo/](https://github.com/RobotWebTools/rclnodejs/tree/develop/ts_demo) -- Electron demos: [electron_demo/](https://github.com/RobotWebTools/rclnodejs/tree/develop/electron_demo) +- TypeScript demos: [demo/typescript/](https://github.com/RobotWebTools/rclnodejs/tree/develop/demo/typescript) +- Electron demos: [demo/electron/](https://github.com/RobotWebTools/rclnodejs/tree/develop/demo/electron) +- WebSocket bridge demo: [demo/rosocket/](https://github.com/RobotWebTools/rclnodejs/tree/develop/demo/rosocket) - Companion CLI: [rclnodejs-cli](https://github.com/RobotWebTools/rclnodejs-cli/) ## Message Generation