Skip to content

Commit caa463b

Browse files
committed
Add functions to run ros2 run/launch
1 parent 95b5609 commit caa463b

File tree

3 files changed

+131
-0
lines changed

3 files changed

+131
-0
lines changed

index.js

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const {
5757
serializeMessage,
5858
deserializeMessage,
5959
} = require('./lib/serialization.js');
60+
const { spawn } = require('child_process');
6061

6162
/**
6263
* Get the version of the generator that was used for the currently present interfaces.
@@ -89,6 +90,79 @@ async function getCurrentGeneratorVersion() {
8990

9091
let _rosVersionChecked = false;
9192

93+
/**
94+
* Run a ROS2 package executable using 'ros2 run' command.
95+
* @param {string} packageName - The name of the ROS2 package.
96+
* @param {string} executableName - The name of the executable to run.
97+
* @param {string[]} [args=[]] - Additional arguments to pass to the executable.
98+
* @return {Promise<{process: ChildProcess}>} A Promise that resolves with the process.
99+
*/
100+
function ros2Run(packageName, executableName, args = []) {
101+
return new Promise((resolve, reject) => {
102+
if (typeof packageName !== 'string' || !packageName.trim()) {
103+
reject(new Error('Package name must be a non-empty string'));
104+
return;
105+
}
106+
107+
if (typeof executableName !== 'string' || !executableName.trim()) {
108+
reject(new Error('Executable name must be a non-empty string'));
109+
return;
110+
}
111+
112+
if (!Array.isArray(args)) {
113+
reject(new Error('Arguments must be an array'));
114+
return;
115+
}
116+
117+
const command = 'ros2';
118+
const cmdArgs = ['run', packageName, executableName, ...args];
119+
const childProcess = spawn(command, cmdArgs);
120+
121+
childProcess.on('error', (error) => {
122+
reject(new Error(`Failed to start ros2 run: ${error.message}`));
123+
});
124+
125+
resolve({
126+
process: childProcess,
127+
});
128+
});
129+
}
130+
131+
/**
132+
* Run a ROS2 launch file using 'ros2 launch' command.
133+
* @param {string} packageName - The name of the ROS2 package.
134+
* @param {string} launchFile - The name of the launch file to run.
135+
* @param {string[]} [args=[]] - Additional arguments to pass to the launch file.
136+
* @return {Promise<{process: ChildProcess}>} A Promise that resolves with the process.
137+
*/
138+
function ros2Launch(packageName, launchFile, args = []) {
139+
return new Promise((resolve, reject) => {
140+
if (typeof packageName !== 'string' || !packageName.trim()) {
141+
reject(new Error('Package name must be a non-empty string'));
142+
return;
143+
}
144+
if (typeof launchFile !== 'string' || !launchFile.trim()) {
145+
reject(new Error('Launch file name must be a non-empty string'));
146+
return;
147+
}
148+
if (!Array.isArray(args)) {
149+
reject(new Error('Arguments must be an array'));
150+
return;
151+
}
152+
const command = 'ros2';
153+
const cmdArgs = ['launch', packageName, launchFile, ...args];
154+
const childProcess = spawn(command, cmdArgs);
155+
156+
childProcess.on('error', (error) => {
157+
reject(new Error(`Failed to start ros2 launch: ${error.message}`));
158+
});
159+
160+
resolve({
161+
process: childProcess,
162+
});
163+
});
164+
}
165+
92166
/**
93167
* A module that exposes the rclnodejs interfaces.
94168
* @exports rclnodejs
@@ -444,6 +518,28 @@ let rcl = {
444518
// this will not throw even if the handler is already removed
445519
process.removeListener('SIGINT', _sigHandler);
446520
},
521+
522+
/**
523+
* Run a ROS2 package executable using 'ros2 run' command.
524+
* @param {string} packageName - The name of the ROS2 package.
525+
* @param {string} executableName - The name of the executable to run.
526+
* @param {string[]} [args=[]] - Additional arguments to pass to the executable.
527+
* @return {Promise<{process: ChildProcess}>} A Promise that resolves with the process.
528+
*/
529+
ros2Run(packageName, executableName, args = []) {
530+
return ros2Run(packageName, executableName, args);
531+
},
532+
533+
/**
534+
* Run a ROS2 launch file using 'ros2 launch' command.
535+
* @param {string} packageName - The name of the ROS2 package.
536+
* @param {string} launchFile - The name of the launch file to run.
537+
* @param {string[]} [args=[]] - Additional arguments to pass to the launch file.
538+
* @return {Promise<{process: ChildProcess}>} A Promise that resolves with the process.
539+
*/
540+
ros2Launch(packageName, launchFile, args = []) {
541+
return ros2Launch(packageName, launchFile, args);
542+
},
447543
};
448544

449545
const _sigHandler = () => {

test/types/index.test-d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { expectType, expectAssignable } from 'tsd';
44
import * as rclnodejs from 'rclnodejs';
5+
import { ChildProcess } from 'child_process';
56

67
const NODE_NAME = 'test_node';
78
const LIFECYCLE_NODE_NAME = 'lifecycle_test_node';
@@ -17,6 +18,12 @@ expectType<string | undefined>(rclnodejs.DistroUtils.getDistroName());
1718
expectType<boolean>(rclnodejs.isShutdown());
1819
expectType<void>(rclnodejs.shutdown());
1920
expectType<void>(rclnodejs.removeSignalHandlers());
21+
expectType<Promise<{ process: ChildProcess }>>(
22+
rclnodejs.ros2Run('package_name', 'executable_name', ['arg1', 'arg2'])
23+
);
24+
expectType<Promise<{ process: ChildProcess }>>(
25+
rclnodejs.ros2Launch('package_name', 'launch_file', ['arg1', 'arg2'])
26+
);
2027

2128
// ---- DistroUtil ----
2229
expectType<rclnodejs.DistroUtils.DistroId>(rclnodejs.DistroUtils.getDistroId());

types/index.d.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
/// <reference path="./base.d.ts" />
22

3+
import { ChildProcess } from 'child_process';
4+
35
declare module 'rclnodejs' {
46
type Class = new (...args: any[]) => any;
57

@@ -207,4 +209,30 @@ declare module 'rclnodejs' {
207209
* @returns An Object representing the deserialized message.
208210
*/
209211
function deserializeMessage(buffer: Buffer, typeClass: Class): object;
212+
213+
/**
214+
* Run a ROS2 package executable using 'ros2 run' command.
215+
* @param {string} packageName - The name of the ROS2 package.
216+
* @param {string} executableName - The name of the executable to run.
217+
* @param {string[]} [args=[]] - Additional arguments to pass to the executable.
218+
* @return {Promise<{process: ChildProcess}>} A Promise that resolves with the process.
219+
*/
220+
function ros2Run(
221+
packageName: string,
222+
executableName: string,
223+
args: string[]
224+
): Promise<{ process: ChildProcess }>;
225+
226+
/**
227+
* Run a ROS2 launch file using 'ros2 launch' command.
228+
* @param {string} packageName - The name of the ROS2 package.
229+
* @param {string} launchFile - The name of the launch file to run.
230+
* @param {string[]} [args=[]] - Additional arguments to pass to the launch file.
231+
* @return {Promise<{process: ChildProcess}>} A Promise that resolves with the process.
232+
*/
233+
function ros2Launch(
234+
packageName: string,
235+
launchFile: string,
236+
args: string[]
237+
): Promise<{ process: ChildProcess }>;
210238
}

0 commit comments

Comments
 (0)