rclnodejs 1.3.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +4 -2
- package/rosidl_convertor/README.md +298 -0
- package/rosidl_convertor/idl_convertor.js +49 -0
- package/rosidl_convertor/idl_convertor.py +1250 -0
- package/rosidl_gen/generator.json +2 -2
- package/rosidl_gen/index.js +21 -4
- package/rosidl_gen/packages.js +65 -32
- package/scripts/generate_messages.js +6 -0
- package/types/interfaces.d.ts +36 -0
- package/scripts/cpplint.js +0 -39
- package/scripts/npm-pack.sh +0 -38
- package/scripts/npmjs-readme.md +0 -169
- package/scripts/run_test.js +0 -49
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rosidl-generator",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Generate JavaScript object from ROS IDL(.msg) files",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Generate JavaScript object from ROS IDL(.msg/.srv/.action/.idl) files",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"authors": [
|
|
7
7
|
"Minggang Wang <minggang.wang@intel.com>",
|
package/rosidl_gen/index.js
CHANGED
|
@@ -18,18 +18,35 @@ const fse = require('fs-extra');
|
|
|
18
18
|
const generateJSStructFromIDL = require('./idl_generator.js');
|
|
19
19
|
const packages = require('./packages.js');
|
|
20
20
|
const path = require('path');
|
|
21
|
-
|
|
21
|
+
const idlConvertor = require('../rosidl_convertor/idl_convertor.js');
|
|
22
22
|
const generatedRoot = path.join(__dirname, '../generated/');
|
|
23
23
|
const serviceMsgPath = path.join(generatedRoot, 'srv_msg');
|
|
24
|
+
const idlPath = path.join(generatedRoot, 'share');
|
|
25
|
+
const useIDL = !!process.argv.find((arg) => arg === '--idl');
|
|
24
26
|
|
|
25
27
|
function getInstalledPackagePaths() {
|
|
26
28
|
return process.env.AMENT_PREFIX_PATH.split(path.delimiter);
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
async function generateInPath(path) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
let pkgsInfo = null;
|
|
33
|
+
if (!useIDL) {
|
|
34
|
+
pkgsInfo = Array.from(
|
|
35
|
+
(await packages.findPackagesInDirectory(path)).values()
|
|
36
|
+
);
|
|
37
|
+
} else {
|
|
38
|
+
const idlPkgs = await packages.findPackagesInDirectory(path, useIDL);
|
|
39
|
+
await fse.ensureDir(idlPath);
|
|
40
|
+
const promises = [];
|
|
41
|
+
idlPkgs.forEach((pkg) => {
|
|
42
|
+
pkg.idls.forEach((idl) => {
|
|
43
|
+
promises.push(idlConvertor(idl.pkgName, idl.filePath, idlPath));
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
await Promise.all(promises);
|
|
47
|
+
const pkgsFromIdl = await packages.findPackagesInDirectory(idlPath, false);
|
|
48
|
+
pkgsInfo = Array.from(pkgsFromIdl.values());
|
|
49
|
+
}
|
|
33
50
|
|
|
34
51
|
await Promise.all(
|
|
35
52
|
pkgsInfo.map((pkgInfo) => generateJSStructFromIDL(pkgInfo, generatedRoot))
|
package/rosidl_gen/packages.js
CHANGED
|
@@ -70,7 +70,13 @@ function grabInterfaceInfo(filePath, amentExecuted) {
|
|
|
70
70
|
function addInterfaceInfo(info, type, pkgMap) {
|
|
71
71
|
let pkgName = info.pkgName;
|
|
72
72
|
if (!pkgMap.has(pkgName)) {
|
|
73
|
-
pkgMap.set(pkgName, {
|
|
73
|
+
pkgMap.set(pkgName, {
|
|
74
|
+
messages: [],
|
|
75
|
+
services: [],
|
|
76
|
+
actions: [],
|
|
77
|
+
idls: [],
|
|
78
|
+
pkgName,
|
|
79
|
+
});
|
|
74
80
|
}
|
|
75
81
|
let pkg = pkgMap.get(pkgName);
|
|
76
82
|
pkg[type].push(info);
|
|
@@ -157,26 +163,32 @@ async function generateMsgForSrv(filePath, interfaceInfo, pkgMap) {
|
|
|
157
163
|
}
|
|
158
164
|
}
|
|
159
165
|
|
|
160
|
-
async function addInterfaceInfos(filePath, dir, pkgMap) {
|
|
161
|
-
const interfaceInfo = grabInterfaceInfo(filePath, true);
|
|
166
|
+
async function addInterfaceInfos(filePath, dir, pkgMap, useIDL) {
|
|
167
|
+
const interfaceInfo = grabInterfaceInfo(filePath, /*amentExecuted=*/ true);
|
|
162
168
|
const ignore = pkgFilters.matchesAny(interfaceInfo);
|
|
163
169
|
if (!ignore) {
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (path.dirname(dir).split(path.sep).pop() !== 'action') {
|
|
168
|
-
addInterfaceInfo(interfaceInfo, 'messages', pkgMap);
|
|
169
|
-
}
|
|
170
|
-
} else if (path.extname(filePath) === '.srv') {
|
|
171
|
-
const requestMsgName = `${path.parse(filePath).name}_Request.msg`;
|
|
172
|
-
if (!fs.existsSync(path.join(path.dirname(filePath), requestMsgName))) {
|
|
173
|
-
await generateMsgForSrv(filePath, interfaceInfo, pkgMap);
|
|
170
|
+
if (useIDL) {
|
|
171
|
+
if (path.extname(filePath) === '.idl') {
|
|
172
|
+
addInterfaceInfo(interfaceInfo, 'idls', pkgMap);
|
|
174
173
|
}
|
|
175
|
-
addInterfaceInfo(interfaceInfo, 'services', pkgMap);
|
|
176
|
-
} else if (path.extname(filePath) === '.action') {
|
|
177
|
-
addInterfaceInfo(interfaceInfo, 'actions', pkgMap);
|
|
178
174
|
} else {
|
|
179
|
-
|
|
175
|
+
if (path.extname(filePath) === '.msg') {
|
|
176
|
+
// Some .msg files were generated prior to 0.3.2 for .action files,
|
|
177
|
+
// which has been disabled. So these files should be ignored here.
|
|
178
|
+
if (path.dirname(dir).split(path.sep).pop() !== 'action') {
|
|
179
|
+
addInterfaceInfo(interfaceInfo, 'messages', pkgMap);
|
|
180
|
+
}
|
|
181
|
+
} else if (path.extname(filePath) === '.srv') {
|
|
182
|
+
const requestMsgName = `${path.parse(filePath).name}_Request.msg`;
|
|
183
|
+
if (!fs.existsSync(path.join(path.dirname(filePath), requestMsgName))) {
|
|
184
|
+
await generateMsgForSrv(filePath, interfaceInfo, pkgMap);
|
|
185
|
+
}
|
|
186
|
+
addInterfaceInfo(interfaceInfo, 'services', pkgMap);
|
|
187
|
+
} else if (path.extname(filePath) === '.action') {
|
|
188
|
+
addInterfaceInfo(interfaceInfo, 'actions', pkgMap);
|
|
189
|
+
} else {
|
|
190
|
+
// we ignore all other files.
|
|
191
|
+
}
|
|
180
192
|
}
|
|
181
193
|
}
|
|
182
194
|
}
|
|
@@ -186,7 +198,7 @@ async function addInterfaceInfos(filePath, dir, pkgMap) {
|
|
|
186
198
|
* @param {string} dir - the directory to search in
|
|
187
199
|
* @return {Promise<Map<string, object>>} A mapping from the package name to some info about it.
|
|
188
200
|
*/
|
|
189
|
-
async function findAmentPackagesInDirectory(dir) {
|
|
201
|
+
async function findAmentPackagesInDirectory(dir, useIDL) {
|
|
190
202
|
const pkgs = await getAmentPackages(dir);
|
|
191
203
|
const files = await Promise.all(
|
|
192
204
|
pkgs.map((pkg) => getPackageDefinitionsFiles(pkg, dir))
|
|
@@ -195,7 +207,7 @@ async function findAmentPackagesInDirectory(dir) {
|
|
|
195
207
|
const rosFiles = files.flat();
|
|
196
208
|
const pkgMap = new Map();
|
|
197
209
|
await Promise.all(
|
|
198
|
-
rosFiles.map((filePath) => addInterfaceInfos(filePath, dir, pkgMap))
|
|
210
|
+
rosFiles.map((filePath) => addInterfaceInfos(filePath, dir, pkgMap, useIDL))
|
|
199
211
|
);
|
|
200
212
|
return pkgMap;
|
|
201
213
|
}
|
|
@@ -205,7 +217,7 @@ async function findAmentPackagesInDirectory(dir) {
|
|
|
205
217
|
* @param {string} dir - the directory to search in
|
|
206
218
|
* @return {Promise<Map<string, object>>} A mapping from the package name to some info about it.
|
|
207
219
|
*/
|
|
208
|
-
async function findPackagesInDirectory(dir) {
|
|
220
|
+
async function findPackagesInDirectory(dir, useIDL) {
|
|
209
221
|
return new Promise((resolve, reject) => {
|
|
210
222
|
let amentExecuted = true;
|
|
211
223
|
|
|
@@ -217,30 +229,51 @@ async function findPackagesInDirectory(dir) {
|
|
|
217
229
|
}
|
|
218
230
|
|
|
219
231
|
if (amentExecuted) {
|
|
220
|
-
return resolve(findAmentPackagesInDirectory(dir));
|
|
232
|
+
return resolve(findAmentPackagesInDirectory(dir, useIDL));
|
|
221
233
|
}
|
|
222
234
|
|
|
223
235
|
let walker = walk.walk(dir, { followLinks: true });
|
|
224
236
|
let pkgMap = new Map();
|
|
225
|
-
walker.on('file', (root, file, next) => {
|
|
237
|
+
walker.on('file', async (root, file, next) => {
|
|
226
238
|
const interfaceInfo = grabInterfaceInfo(
|
|
227
239
|
path.join(root, file.name),
|
|
228
240
|
amentExecuted
|
|
229
241
|
);
|
|
230
242
|
const ignore = pkgFilters.matchesAny(interfaceInfo);
|
|
231
243
|
if (!ignore) {
|
|
232
|
-
if (
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if (path.dirname(root).split(path.sep).pop() !== 'action') {
|
|
236
|
-
addInterfaceInfo(interfaceInfo, 'messages', pkgMap);
|
|
244
|
+
if (useIDL) {
|
|
245
|
+
if (path.extname(file.name) === '.idl') {
|
|
246
|
+
addInterfaceInfo(interfaceInfo, 'idls', pkgMap);
|
|
237
247
|
}
|
|
238
|
-
} else if (path.extname(file.name) === '.srv') {
|
|
239
|
-
addInterfaceInfo(interfaceInfo, 'services', pkgMap);
|
|
240
|
-
} else if (path.extname(file.name) === '.action') {
|
|
241
|
-
addInterfaceInfo(interfaceInfo, 'actions', pkgMap);
|
|
242
248
|
} else {
|
|
243
|
-
|
|
249
|
+
if (path.extname(file.name) === '.msg') {
|
|
250
|
+
// Some .msg files were generated prior to 0.3.2 for .action files,
|
|
251
|
+
// which has been disabled. So these files should be ignored here.
|
|
252
|
+
if (path.dirname(root).split(path.sep).pop() !== 'action') {
|
|
253
|
+
addInterfaceInfo(interfaceInfo, 'messages', pkgMap);
|
|
254
|
+
}
|
|
255
|
+
} else if (path.extname(file.name) === '.srv') {
|
|
256
|
+
const requestMsgName = `${path.parse(interfaceInfo.filePath).name}_Request.msg`;
|
|
257
|
+
if (
|
|
258
|
+
!fs.existsSync(
|
|
259
|
+
path.join(
|
|
260
|
+
path.dirname(interfaceInfo.filePath),
|
|
261
|
+
requestMsgName
|
|
262
|
+
)
|
|
263
|
+
)
|
|
264
|
+
) {
|
|
265
|
+
await generateMsgForSrv(
|
|
266
|
+
interfaceInfo.filePath,
|
|
267
|
+
interfaceInfo,
|
|
268
|
+
pkgMap
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
addInterfaceInfo(interfaceInfo, 'services', pkgMap);
|
|
272
|
+
} else if (path.extname(file.name) === '.action') {
|
|
273
|
+
addInterfaceInfo(interfaceInfo, 'actions', pkgMap);
|
|
274
|
+
} else {
|
|
275
|
+
// we ignore all other files
|
|
276
|
+
}
|
|
244
277
|
}
|
|
245
278
|
}
|
|
246
279
|
next();
|
|
@@ -19,9 +19,15 @@
|
|
|
19
19
|
|
|
20
20
|
const generator = require('../rosidl_gen/index.js');
|
|
21
21
|
const tsdGenerator = require('../rostsd_gen/index.js');
|
|
22
|
+
const useIDL = !!process.argv.find((arg) => arg === '--idl');
|
|
22
23
|
|
|
23
24
|
async function main() {
|
|
24
25
|
console.log('Start generation of ROS2 JavaScript messages...');
|
|
26
|
+
if (!useIDL) {
|
|
27
|
+
console.log(
|
|
28
|
+
'See details https://github.com/RobotWebTools/rclnodejs?tab=readme-ov-file#idl-message-generation for generating from .idl files'
|
|
29
|
+
);
|
|
30
|
+
}
|
|
25
31
|
|
|
26
32
|
try {
|
|
27
33
|
await generator.generateAll(true);
|
package/types/interfaces.d.ts
CHANGED
|
@@ -1312,6 +1312,20 @@ declare module 'rclnodejs' {
|
|
|
1312
1312
|
export interface PolygonConstructor {
|
|
1313
1313
|
new(other?: Polygon): Polygon;
|
|
1314
1314
|
}
|
|
1315
|
+
export interface PolygonInstance {
|
|
1316
|
+
polygon: geometry_msgs.msg.Polygon;
|
|
1317
|
+
id: bigint;
|
|
1318
|
+
}
|
|
1319
|
+
export interface PolygonInstanceConstructor {
|
|
1320
|
+
new(other?: PolygonInstance): PolygonInstance;
|
|
1321
|
+
}
|
|
1322
|
+
export interface PolygonInstanceStamped {
|
|
1323
|
+
header: std_msgs.msg.Header;
|
|
1324
|
+
polygon: geometry_msgs.msg.PolygonInstance;
|
|
1325
|
+
}
|
|
1326
|
+
export interface PolygonInstanceStampedConstructor {
|
|
1327
|
+
new(other?: PolygonInstanceStamped): PolygonInstanceStamped;
|
|
1328
|
+
}
|
|
1315
1329
|
export interface PolygonStamped {
|
|
1316
1330
|
header: std_msgs.msg.Header;
|
|
1317
1331
|
polygon: geometry_msgs.msg.Polygon;
|
|
@@ -1537,6 +1551,20 @@ declare module 'rclnodejs' {
|
|
|
1537
1551
|
export interface PolygonConstructor {
|
|
1538
1552
|
new(other?: Polygon): Polygon;
|
|
1539
1553
|
}
|
|
1554
|
+
export interface PolygonInstance {
|
|
1555
|
+
polygon: 'geometry_msgs/msg/Polygon';
|
|
1556
|
+
id: 'int64';
|
|
1557
|
+
}
|
|
1558
|
+
export interface PolygonInstanceConstructor {
|
|
1559
|
+
new(other?: PolygonInstance): PolygonInstance;
|
|
1560
|
+
}
|
|
1561
|
+
export interface PolygonInstanceStamped {
|
|
1562
|
+
header: 'std_msgs/msg/Header';
|
|
1563
|
+
polygon: 'geometry_msgs/msg/PolygonInstance';
|
|
1564
|
+
}
|
|
1565
|
+
export interface PolygonInstanceStampedConstructor {
|
|
1566
|
+
new(other?: PolygonInstanceStamped): PolygonInstanceStamped;
|
|
1567
|
+
}
|
|
1540
1568
|
export interface PolygonStamped {
|
|
1541
1569
|
header: 'std_msgs/msg/Header';
|
|
1542
1570
|
polygon: 'geometry_msgs/msg/Polygon';
|
|
@@ -7378,6 +7406,8 @@ declare module 'rclnodejs' {
|
|
|
7378
7406
|
'geometry_msgs/msg/Point32': geometry_msgs.msg.Point32,
|
|
7379
7407
|
'geometry_msgs/msg/PointStamped': geometry_msgs.msg.PointStamped,
|
|
7380
7408
|
'geometry_msgs/msg/Polygon': geometry_msgs.msg.Polygon,
|
|
7409
|
+
'geometry_msgs/msg/PolygonInstance': geometry_msgs.msg.PolygonInstance,
|
|
7410
|
+
'geometry_msgs/msg/PolygonInstanceStamped': geometry_msgs.msg.PolygonInstanceStamped,
|
|
7381
7411
|
'geometry_msgs/msg/PolygonStamped': geometry_msgs.msg.PolygonStamped,
|
|
7382
7412
|
'geometry_msgs/msg/Pose': geometry_msgs.msg.Pose,
|
|
7383
7413
|
'geometry_msgs/msg/Pose2D': geometry_msgs.msg.Pose2D,
|
|
@@ -7408,6 +7438,8 @@ declare module 'rclnodejs' {
|
|
|
7408
7438
|
'geometry_msgs/msg/descriptor/Point32': geometry_msgs.msg.descriptor.Point32,
|
|
7409
7439
|
'geometry_msgs/msg/descriptor/PointStamped': geometry_msgs.msg.descriptor.PointStamped,
|
|
7410
7440
|
'geometry_msgs/msg/descriptor/Polygon': geometry_msgs.msg.descriptor.Polygon,
|
|
7441
|
+
'geometry_msgs/msg/descriptor/PolygonInstance': geometry_msgs.msg.descriptor.PolygonInstance,
|
|
7442
|
+
'geometry_msgs/msg/descriptor/PolygonInstanceStamped': geometry_msgs.msg.descriptor.PolygonInstanceStamped,
|
|
7411
7443
|
'geometry_msgs/msg/descriptor/PolygonStamped': geometry_msgs.msg.descriptor.PolygonStamped,
|
|
7412
7444
|
'geometry_msgs/msg/descriptor/Pose': geometry_msgs.msg.descriptor.Pose,
|
|
7413
7445
|
'geometry_msgs/msg/descriptor/Pose2D': geometry_msgs.msg.descriptor.Pose2D,
|
|
@@ -8129,6 +8161,8 @@ declare module 'rclnodejs' {
|
|
|
8129
8161
|
'geometry_msgs/msg/Point32': geometry_msgs.msg.Point32Constructor,
|
|
8130
8162
|
'geometry_msgs/msg/PointStamped': geometry_msgs.msg.PointStampedConstructor,
|
|
8131
8163
|
'geometry_msgs/msg/Polygon': geometry_msgs.msg.PolygonConstructor,
|
|
8164
|
+
'geometry_msgs/msg/PolygonInstance': geometry_msgs.msg.PolygonInstanceConstructor,
|
|
8165
|
+
'geometry_msgs/msg/PolygonInstanceStamped': geometry_msgs.msg.PolygonInstanceStampedConstructor,
|
|
8132
8166
|
'geometry_msgs/msg/PolygonStamped': geometry_msgs.msg.PolygonStampedConstructor,
|
|
8133
8167
|
'geometry_msgs/msg/Pose': geometry_msgs.msg.PoseConstructor,
|
|
8134
8168
|
'geometry_msgs/msg/Pose2D': geometry_msgs.msg.Pose2DConstructor,
|
|
@@ -8159,6 +8193,8 @@ declare module 'rclnodejs' {
|
|
|
8159
8193
|
'geometry_msgs/msg/descriptor/Point32': geometry_msgs.msg.descriptor.Point32Constructor,
|
|
8160
8194
|
'geometry_msgs/msg/descriptor/PointStamped': geometry_msgs.msg.descriptor.PointStampedConstructor,
|
|
8161
8195
|
'geometry_msgs/msg/descriptor/Polygon': geometry_msgs.msg.descriptor.PolygonConstructor,
|
|
8196
|
+
'geometry_msgs/msg/descriptor/PolygonInstance': geometry_msgs.msg.descriptor.PolygonInstanceConstructor,
|
|
8197
|
+
'geometry_msgs/msg/descriptor/PolygonInstanceStamped': geometry_msgs.msg.descriptor.PolygonInstanceStampedConstructor,
|
|
8162
8198
|
'geometry_msgs/msg/descriptor/PolygonStamped': geometry_msgs.msg.descriptor.PolygonStampedConstructor,
|
|
8163
8199
|
'geometry_msgs/msg/descriptor/Pose': geometry_msgs.msg.descriptor.PoseConstructor,
|
|
8164
8200
|
'geometry_msgs/msg/descriptor/Pose2D': geometry_msgs.msg.descriptor.Pose2DConstructor,
|
package/scripts/cpplint.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2017 Intel Corporation. All rights reserved.
|
|
2
|
-
|
|
3
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
// you may not use this file except in compliance with the License.
|
|
5
|
-
// You may obtain a copy of the License at
|
|
6
|
-
|
|
7
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
|
|
9
|
-
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
// See the License for the specific language governing permissions and
|
|
13
|
-
// limitations under the License.
|
|
14
|
-
|
|
15
|
-
'use strict';
|
|
16
|
-
|
|
17
|
-
const exec = require('child_process').exec;
|
|
18
|
-
|
|
19
|
-
const cmd = 'wget -nc ';
|
|
20
|
-
const cpplintUrl =
|
|
21
|
-
'https://raw.githubusercontent.com/cpplint/cpplint/refs/heads/develop/cpplint.py';
|
|
22
|
-
const root = `${__dirname}/../src`;
|
|
23
|
-
const args = `--filter=-build/include_subdir,-whitespace/indent_namespace --extensions=cpp,h,hpp,cc ${root}/*`;
|
|
24
|
-
|
|
25
|
-
console.log('Downloading the cpplint...');
|
|
26
|
-
exec(cmd + cpplintUrl, (err, stdout, stderr) => {
|
|
27
|
-
if (err) {
|
|
28
|
-
console.log(`Downloading failed: ${stderr}`);
|
|
29
|
-
} else {
|
|
30
|
-
console.log('Running the cpplint...');
|
|
31
|
-
exec('python3 cpplint.py ' + args, (err, stdout, stderr) => {
|
|
32
|
-
console.log(stdout);
|
|
33
|
-
if (err) {
|
|
34
|
-
console.log(stderr);
|
|
35
|
-
throw Error('cpplint failed.');
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
});
|
package/scripts/npm-pack.sh
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
#
|
|
3
|
-
# Copyright (c) 2017 Intel Corporation. All rights reserved.
|
|
4
|
-
|
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
# you may not use this file except in compliance with the License.
|
|
7
|
-
# You may obtain a copy of the License at
|
|
8
|
-
|
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
|
|
11
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
# See the License for the specific language governing permissions and
|
|
15
|
-
# limitations under the License.
|
|
16
|
-
|
|
17
|
-
#Usage: npm-pack.sh
|
|
18
|
-
|
|
19
|
-
WORKDIR=`mktemp -d`
|
|
20
|
-
RAWMODULEDIR="rclnodejs/"
|
|
21
|
-
MODULEDIR="$WORKDIR/$RAWMODULEDIR"
|
|
22
|
-
|
|
23
|
-
mkdir -p $MODULEDIR
|
|
24
|
-
rsync -a . $MODULEDIR
|
|
25
|
-
|
|
26
|
-
cp -f scripts/npmjs-readme.md $MODULEDIR/README.md
|
|
27
|
-
|
|
28
|
-
pushd . > /dev/null
|
|
29
|
-
cd $WORKDIR
|
|
30
|
-
FILENAME=`npm pack $RAWMODULEDIR | awk '{for(i=1; i<=NF; i++) if ($i ~ /rclnodejs-.*\.tgz/) print $i}'`
|
|
31
|
-
TARFILENAME="$WORKDIR/$FILENAME"
|
|
32
|
-
|
|
33
|
-
popd > /dev/null
|
|
34
|
-
mkdir -p dist
|
|
35
|
-
cp -f $TARFILENAME ./dist/
|
|
36
|
-
rm -rf $WORKDIR
|
|
37
|
-
|
|
38
|
-
echo "Generated ./dist/$FILENAME"
|
package/scripts/npmjs-readme.md
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
# rclnodejs [](https://github.com/RobotWebTools/rclnodejs/actions/workflows/linux-x64-build-and-test.yml?query=branch%3Adevelop)[](https://github.com/RobotWebTools/rclnodejs/actions/workflows/linux-arm64-build-and-test.yml?query=branch%3Adevelop)
|
|
2
|
-
|
|
3
|
-
`rclnodejs` is a Node.js client for the Robot Operating System (ROS 2). It provides a simple and easy JavaScript API for ROS 2 programming. TypeScript declarations are included to support use of rclnodejs in TypeScript projects.
|
|
4
|
-
|
|
5
|
-
Here's an example for how to create a ROS 2 node that publishes a string message in a few lines of JavaScript.
|
|
6
|
-
|
|
7
|
-
```JavaScript
|
|
8
|
-
const rclnodejs = require('rclnodejs');
|
|
9
|
-
rclnodejs.init().then(() => {
|
|
10
|
-
const node = rclnodejs.createNode('publisher_example_node');
|
|
11
|
-
const publisher = node.createPublisher('std_msgs/msg/String', 'topic');
|
|
12
|
-
publisher.publish(`Hello ROS 2 from rclnodejs`);
|
|
13
|
-
rclnodejs.spin(node);
|
|
14
|
-
});
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Prerequisites
|
|
18
|
-
|
|
19
|
-
**Node.js**
|
|
20
|
-
|
|
21
|
-
- [Node.js](https://nodejs.org/en/) version >= 16.13.0.
|
|
22
|
-
|
|
23
|
-
**ROS 2 SDK**
|
|
24
|
-
|
|
25
|
-
- See the ROS 2 SDK [Installation Guide](https://docs.ros.org/en/kilted/Installation.html) for details.
|
|
26
|
-
- **DON'T FORGET TO [SOURCE THE ROS 2 STARTUP FILES](https://docs.ros.org/en/kilted/Tutorials/Beginner-CLI-Tools/Configuring-ROS2-Environment.htmls)**
|
|
27
|
-
|
|
28
|
-
## Install rclnodejs
|
|
29
|
-
|
|
30
|
-
Install the rclnodejs version that is compatible with your installed version of ROS 2 (see table below).
|
|
31
|
-
|
|
32
|
-
Run the following command for the most current version of rclnodejs
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
npm i rclnodejs
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
or to install a specific version of rclnodejs use
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
npm i rclnodejs@x.y.z
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
#### RCLNODEJS - ROS 2 Version Compatibility
|
|
45
|
-
|
|
46
|
-
| RCLNODEJS Version | Compatible ROS 2 LTS |
|
|
47
|
-
| :----------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
|
48
|
-
| latest version (currently [v1.3.0](https://github.com/RobotWebTools/rclnodejs/tree/1.3.0)) | [Kilted](https://github.com/RobotWebTools/rclnodejs/tree/kilted)<br>[Jazzy](https://github.com/RobotWebTools/rclnodejs/tree/jazzy)<br>[Humble](https://github.com/RobotWebTools/rclnodejs/tree/humble-hawksbill) |
|
|
49
|
-
|
|
50
|
-
## Documentation
|
|
51
|
-
|
|
52
|
-
API [documentation](https://robotwebtools.github.io/rclnodejs/docs/index.html) is available online.
|
|
53
|
-
|
|
54
|
-
## JavaScript Examples
|
|
55
|
-
|
|
56
|
-
The source for the following examples and many others can be found [here](https://github.com/RobotWebTools/rclnodejs/tree/develop/example).
|
|
57
|
-
|
|
58
|
-
Use complex message
|
|
59
|
-
|
|
60
|
-
```JavaScript
|
|
61
|
-
const publisher = node.createPublisher('sensor_msgs/msg/JointState', 'topic');
|
|
62
|
-
publisher.publish({
|
|
63
|
-
header: {
|
|
64
|
-
stamp: {
|
|
65
|
-
sec: 123456,
|
|
66
|
-
nanosec: 789,
|
|
67
|
-
},
|
|
68
|
-
frame_id: 'main frame',
|
|
69
|
-
},
|
|
70
|
-
name: ['Tom', 'Jerry'],
|
|
71
|
-
position: [1, 2],
|
|
72
|
-
velocity: [2, 3],
|
|
73
|
-
effort: [4, 5, 6],
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Create a subscription
|
|
79
|
-
|
|
80
|
-
```JavaScript
|
|
81
|
-
const rclnodejs = require('../index.js');
|
|
82
|
-
|
|
83
|
-
// Create a ROS node and then print out the string message received from publishers
|
|
84
|
-
rclnodejs.init().then(() => {
|
|
85
|
-
const node = rclnodejs.createNode('subscription_example_node');
|
|
86
|
-
|
|
87
|
-
node.createSubscription('std_msgs/msg/String', 'topic', (msg) => {
|
|
88
|
-
console.log(`Received message: ${typeof msg}`, msg);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
rclnodejs.spin(node);
|
|
92
|
-
});
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
Create a service
|
|
96
|
-
|
|
97
|
-
```JavaScript
|
|
98
|
-
node.createService('example_interfaces/srv/AddTwoInts', 'add_two_ints', (request, response) => {
|
|
99
|
-
console.log(`Incoming request: ${typeof request}`, request);
|
|
100
|
-
let result = response.template;
|
|
101
|
-
result.sum = request.a + request.b;
|
|
102
|
-
console.log(`Sending response: ${typeof result}`, result, '\n--');
|
|
103
|
-
response.send(result);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
Send a request in a client
|
|
109
|
-
|
|
110
|
-
```JavaScript
|
|
111
|
-
const client = node.createClient('example_interfaces/srv/AddTwoInts', 'add_two_ints');
|
|
112
|
-
const request = {
|
|
113
|
-
a: Math.floor(Math.random() * 100),
|
|
114
|
-
b: Math.floor(Math.random() * 100),
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
console.log(`Sending: ${typeof request}`, request);
|
|
118
|
-
client.sendRequest(request, (response) => {
|
|
119
|
-
console.log(`Result: ${typeof response}`, response);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
## Using rclnodejs with TypeScript
|
|
125
|
-
|
|
126
|
-
In your node project install the rclnodejs package as described above. You will also need the TypeScript compiler and node typings installed.
|
|
127
|
-
|
|
128
|
-
```
|
|
129
|
-
npm install typescript @types/node -D
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
In your project's tsconfig.json file include the following compiler options:
|
|
133
|
-
|
|
134
|
-
```jsonc
|
|
135
|
-
{
|
|
136
|
-
"compilerOptions": {
|
|
137
|
-
"module": "commonjs",
|
|
138
|
-
"moduleResolution": "node",
|
|
139
|
-
"target": "es6",
|
|
140
|
-
...
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
Here's an earlier JavaScript example reimplemented in TypeScript.
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
import * as rclnodejs from 'rclnodejs';
|
|
149
|
-
rclnodejs.init().then(() => {
|
|
150
|
-
const node = rclnodejs.createNode('publisher_example_node');
|
|
151
|
-
const publisher = node.createPublisher('std_msgs/msg/String', 'topic');
|
|
152
|
-
publisher.publish(`Hello ROS 2 from rclnodejs`);
|
|
153
|
-
rclnodejs.spin(node);
|
|
154
|
-
});
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
Type-aliases for the ROS2 messages can be found in the `types/interfaces.d.ts` file. To use a message type-alias follow the naming pattern <pkg_name>.[msg|srv].<type>, e.g., sensor_msgs.msg.LaserScan or the std_msgs.msg.String as shown below.
|
|
158
|
-
|
|
159
|
-
```typescript
|
|
160
|
-
const msg: rclnodejs.std_msgs.msg.String = {
|
|
161
|
-
data: 'hello ROS2 from rclnodejs',
|
|
162
|
-
};
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
**Note** that the interface.d.ts file is updated each time the generate_messages.js script is run.
|
|
166
|
-
|
|
167
|
-
## License
|
|
168
|
-
|
|
169
|
-
Apache License Version 2.0
|
package/scripts/run_test.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2017 Intel Corporation. All rights reserved.
|
|
2
|
-
|
|
3
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
// you may not use this file except in compliance with the License.
|
|
5
|
-
// You may obtain a copy of the License at
|
|
6
|
-
|
|
7
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
|
|
9
|
-
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
// See the License for the specific language governing permissions and
|
|
13
|
-
// limitations under the License.
|
|
14
|
-
|
|
15
|
-
'use strict';
|
|
16
|
-
|
|
17
|
-
const fs = require('fs-extra');
|
|
18
|
-
const Mocha = require('mocha');
|
|
19
|
-
const os = require('os');
|
|
20
|
-
const path = require('path');
|
|
21
|
-
|
|
22
|
-
fs.remove(path.join(path.dirname(__dirname), 'generated'), (err) => {
|
|
23
|
-
if (!err) {
|
|
24
|
-
let mocha = new Mocha();
|
|
25
|
-
const testDir = path.join(__dirname, '../test/');
|
|
26
|
-
// eslint-disable-next-line
|
|
27
|
-
const tests = fs.readdirSync(testDir).filter((file) => {
|
|
28
|
-
return file.substr(0, 5) === 'test-';
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
// eslint-disable-next-line
|
|
32
|
-
let blocklist = JSON.parse(
|
|
33
|
-
fs.readFileSync(path.join(__dirname, '../test/blocklist.json'), 'utf8')
|
|
34
|
-
);
|
|
35
|
-
let ignoredCases = blocklist[os.type()];
|
|
36
|
-
|
|
37
|
-
tests.forEach((test) => {
|
|
38
|
-
if (ignoredCases.indexOf(test) === -1) {
|
|
39
|
-
mocha.addFile(path.join(testDir, test));
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
mocha.run(function (failures) {
|
|
44
|
-
process.on('exit', () => {
|
|
45
|
-
process.exit(failures);
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
});
|