This demo showcases how to use rclnodejs with Electron to create an interactive car control application. The demo features a virtual joystick that publishes ROS2 velocity commands and a car visualization that responds to those commands in real-time.
- Directional Controls: Up/Down/Left/Right buttons for car movement
- Stop Button: Emergency stop functionality
- Keyboard Support: WASD and arrow keys for control
- Real-time Status: Display current command and velocity values
- Real-time Movement: Car moves and rotates based on received commands
- Position Tracking: Shows current position (North/South/East/West/Center)
- Visual Feedback: Color-coded movement indicators
- Command Counter: Tracks total number of commands received
- Topic:
cmd_vel(geometry_msgs/Twist) - Publisher: Sends velocity commands
- Subscriber: Receives and displays velocity commands
- Node Name:
car_control_node
Before running this demo, ensure you have:
- ROS2 installed (Humble, Jazzy, Kilted, Lyrical, or Rolling)
- Node.js (version 20.20.2 or higher)
- rclnodejs built and working
# Source your ROS2 installation
source /opt/ros/<your-ros-distro>/setup.bash
# Verify ROS2 is working
ros2 topic listFrom the main rclnodejs directory:
npm install
npm run build-
Navigate to the demo directory:
cd electron_car_demo -
Install dependencies:
npm install
-
Rebuild native modules for Electron:
npm run rebuild
-
Start the demo:
# Make sure ROS2 is sourced first source /opt/ros/<your-ros-distro>/setup.bash npm start
You can package the application into a standalone folder using Electron Forge.
Run the following command to create a distributable executable:
npm run packageThe output will be located in the out/ directory.
Technical Note on ASAR: We enable ASAR but configure it to unpack the rclnodejs module. rclnodejs (v1.8.1+) requires file system access to generated code and native bindings, so we use the asar.unpack configuration in package.json to keep rclnodejs files accessible on disk while packing the rest of the application.
"config": {
"forge": {
"packagerConfig": {
"asar": {
"unpack": "**/node_modules/rclnodejs/**"
}
}
}
}To create a .zip file or other platform-specific installers (deb/rpm), run:
npm run makeNote: Creating DEB/RPM installers requires system tools like dpkg and fakeroot. For ZIP files, you need zip.
Even as a standalone application, ROS 2 must be installed and sourced on the target machine because rclnodejs links dynamically to the ROS 2 shared libraries.
# Source ROS2 environment
source /opt/ros/<your-ros-distro>/setup.bash
# Run the packaged executable
./out/rclnodejs-electron-car-demo-linux-x64/rclnodejs-electron-car-demo- Click the directional buttons (โโโโ) on the joystick
- Click the red STOP button to halt movement
- W or โ: Move forward
- S or โ: Move backward
- A or โ: Turn left
- D or โ: Turn right
- Space or Esc: Stop
- Command: Shows the current command being sent
- Linear X: Forward/backward velocity (m/s)
- Angular Z: Rotation velocity (rad/s)
- Topic: ROS2 topic name (
cmd_vel)
- Received Commands: Total count of commands received
- Last Command: Most recent command processed
- Car Position: Current position in the visualization area
The demo uses geometry_msgs/Twist messages with the following structure:
{
linear: {
x: 1.0, // Forward/backward velocity (m/s)
y: 0.0, // Left/right velocity (typically 0 for cars)
z: 0.0 // Up/down velocity (typically 0 for ground vehicles)
},
angular: {
x: 0.0, // Roll rate (typically 0 for cars)
y: 0.0, // Pitch rate (typically 0 for cars)
z: 1.0 // Yaw rate (turning left/right in rad/s)
}
}| Command | Linear X | Angular Z | Description |
|---|---|---|---|
| Forward | +1.0 | 0.0 | Move forward at 1 m/s |
| Backward | -1.0 | 0.0 | Move backward at 1 m/s |
| Left | 0.0 | +1.0 | Turn left at 1 rad/s |
| Right | 0.0 | -1.0 | Turn right at 1 rad/s |
| Stop | 0.0 | 0.0 | Stop all movement |
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ Renderer โ โ Main Process โ โ ROS2 Network โ
โ (UI/Browser) โ โ (Node.js) โ โ โ
โโโโโโโโโโโโโโโโโโโค โโโโโโโโโโโโโโโโโโโโค โโโโโโโโโโโโโโโโโโโค
โ โข Joystick UI โโโโโถโ โข rclnodejs Node โโโโโถโ โข cmd_vel Topic โ
โ โข Car Display โโโโโโ โข Publisher โ โ โข Other Nodes โ
โ โข Status Panel โ โ โข Subscriber โโโโโโ โข Robot/Sim โ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
You can test the demo using standard ROS2 command-line tools:
# In a new terminal (with ROS2 sourced)
ros2 topic echo /cmd_vel# Send a forward command
ros2 topic pub /cmd_vel geometry_msgs/Twist "linear: {x: 1.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}"
# Send a turn left command
ros2 topic pub /cmd_vel geometry_msgs/Twist "linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.0}"
# Stop command
ros2 topic pub /cmd_vel geometry_msgs/Twist "linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}"ros2 topic list
ros2 topic info /cmd_vel
ros2 topic hz /cmd_velThis demo can be easily connected to real robots or simulators:
# Launch TurtleBot3 simulation
ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py
# The demo will automatically control the robot via cmd_vel topicEnsure your robot subscribes to the /cmd_vel topic with geometry_msgs/Twist messages.
Edit the speed and turnSpeed constants in main.js:
const speed = 1.0; // Linear velocity (m/s)
const turnSpeed = 1.0; // Angular velocity (rad/s)Modify the topic name in main.js:
// Change 'cmd_vel' to your desired topic name
carControlPublisher = carControlNode.createPublisher(
'geometry_msgs/msg/Twist',
'your_topic_name'
);Extend the joystick commands by modifying the switch statement in main.js and adding corresponding UI elements.
-
"Failed to initialize ROS2" Error
- Ensure ROS2 is properly sourced before running npm start
- Check that rclnodejs is built correctly
-
Native Module Rebuild Issues
npm run rebuild # or manually: ./node_modules/.bin/electron-rebuild -
Topic Not Appearing
- Verify ROS2 daemon is running:
ros2 daemon status - Check topic list:
ros2 topic list
- Verify ROS2 daemon is running:
-
Car Not Moving in UI
- Check browser console for JavaScript errors
- Verify IPC communication between main and renderer processes
Add debug logging by modifying main.js:
// Enable debug logging
console.log('Publishing command:', command, twist);This demo is licensed under the Apache License 2.0, same as the main rclnodejs project.
Feel free to submit issues and enhancement requests! This demo serves as both a functional example and a starting point for more complex ROS2 Electron applications.
