rclnodejs 1.4.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 +2 -2
- package/rosidl_convertor/idl_convertor.py +107 -33
- 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
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ npm i rclnodejs@x.y.z
|
|
|
45
45
|
|
|
46
46
|
| RCLNODEJS Version | Compatible ROS 2 LTS |
|
|
47
47
|
| :----------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
|
48
|
-
| latest version (currently [v1.4.
|
|
48
|
+
| latest version (currently [v1.4.1](https://github.com/RobotWebTools/rclnodejs/tree/1.4.1)) | [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
49
|
|
|
50
50
|
## Documentation
|
|
51
51
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rclnodejs",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "ROS2.0 JavaScript client with Node.js",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@typescript-eslint/eslint-plugin": "^8.18.0",
|
|
53
53
|
"@typescript-eslint/parser": "^8.18.0",
|
|
54
54
|
"clang-format": "^1.8.0",
|
|
55
|
-
"commander": "^
|
|
55
|
+
"commander": "^14.0.0",
|
|
56
56
|
"coveralls": "^3.1.1",
|
|
57
57
|
"deep-equal": "^2.2.3",
|
|
58
58
|
"eslint": "^9.16.0",
|
|
@@ -190,37 +190,85 @@ class IdlParser:
|
|
|
190
190
|
return interfaces
|
|
191
191
|
|
|
192
192
|
def _preprocess_content(self, content: str) -> str:
|
|
193
|
-
"""Remove
|
|
194
|
-
# Remove @verbatim blocks using a more robust approach
|
|
195
|
-
# Find and remove complete @verbatim blocks that may span multiple lines
|
|
193
|
+
"""Remove @verbatim blocks from the content with proper string handling."""
|
|
196
194
|
lines = content.split('\n')
|
|
197
|
-
|
|
198
|
-
in_verbatim = False
|
|
199
|
-
paren_count = 0
|
|
200
|
-
|
|
201
|
-
for line in lines:
|
|
202
|
-
if '@verbatim' in line and not in_verbatim:
|
|
203
|
-
in_verbatim = True
|
|
204
|
-
paren_count = line.count('(') - line.count(')')
|
|
205
|
-
continue
|
|
206
|
-
elif in_verbatim:
|
|
207
|
-
paren_count += line.count('(') - line.count(')')
|
|
208
|
-
if paren_count <= 0:
|
|
209
|
-
in_verbatim = False
|
|
210
|
-
continue
|
|
195
|
+
result_lines = []
|
|
211
196
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
197
|
+
i = 0
|
|
198
|
+
while i < len(lines):
|
|
199
|
+
line = lines[i]
|
|
200
|
+
if '@verbatim' in line:
|
|
201
|
+
# Find opening parenthesis after @verbatim
|
|
202
|
+
verbatim_pos = line.find('@verbatim')
|
|
203
|
+
paren_pos = line.find('(', verbatim_pos)
|
|
204
|
+
if paren_pos == -1:
|
|
205
|
+
result_lines.append(line)
|
|
206
|
+
i += 1
|
|
207
|
+
continue
|
|
208
|
+
|
|
209
|
+
# Parse with string awareness
|
|
210
|
+
paren_count = 0
|
|
211
|
+
in_string = False
|
|
212
|
+
escape_next = False
|
|
213
|
+
start_part = line[:verbatim_pos]
|
|
214
|
+
|
|
215
|
+
# Process current line starting from opening parenthesis
|
|
216
|
+
j = paren_pos
|
|
217
|
+
while j < len(line):
|
|
218
|
+
char = line[j]
|
|
219
|
+
|
|
220
|
+
if escape_next:
|
|
221
|
+
escape_next = False
|
|
222
|
+
elif char == '\\':
|
|
223
|
+
escape_next = True
|
|
224
|
+
elif char == '"' and not escape_next:
|
|
225
|
+
in_string = not in_string
|
|
226
|
+
elif not in_string:
|
|
227
|
+
if char == '(':
|
|
228
|
+
paren_count += 1
|
|
229
|
+
elif char == ')':
|
|
230
|
+
paren_count -= 1
|
|
231
|
+
if paren_count == 0:
|
|
232
|
+
# Found end of verbatim block
|
|
233
|
+
result_lines.append(start_part + line[j+1:])
|
|
234
|
+
i += 1
|
|
235
|
+
break
|
|
236
|
+
j += 1
|
|
237
|
+
else:
|
|
238
|
+
# Verbatim block continues to next lines
|
|
239
|
+
i += 1
|
|
240
|
+
while i < len(lines) and paren_count > 0:
|
|
241
|
+
line = lines[i]
|
|
242
|
+
j = 0
|
|
243
|
+
while j < len(line):
|
|
244
|
+
char = line[j]
|
|
245
|
+
|
|
246
|
+
if escape_next:
|
|
247
|
+
escape_next = False
|
|
248
|
+
elif char == '\\':
|
|
249
|
+
escape_next = True
|
|
250
|
+
elif char == '"' and not escape_next:
|
|
251
|
+
in_string = not in_string
|
|
252
|
+
elif not in_string:
|
|
253
|
+
if char == '(':
|
|
254
|
+
paren_count += 1
|
|
255
|
+
elif char == ')':
|
|
256
|
+
paren_count -= 1
|
|
257
|
+
if paren_count == 0:
|
|
258
|
+
# Found end
|
|
259
|
+
result_lines.append(start_part + line[j+1:])
|
|
260
|
+
i += 1
|
|
261
|
+
break
|
|
262
|
+
j += 1
|
|
263
|
+
else:
|
|
264
|
+
i += 1
|
|
265
|
+
continue
|
|
266
|
+
break
|
|
267
|
+
else:
|
|
268
|
+
result_lines.append(line)
|
|
269
|
+
i += 1
|
|
222
270
|
|
|
223
|
-
return
|
|
271
|
+
return '\n'.join(result_lines)
|
|
224
272
|
|
|
225
273
|
def _extract_modules(self, content: str) -> List[Dict]:
|
|
226
274
|
"""Extract module definitions from content"""
|
|
@@ -260,11 +308,37 @@ class IdlParser:
|
|
|
260
308
|
nested['name'] = f"{module_name}::{nested['name']}"
|
|
261
309
|
modules.append(nested)
|
|
262
310
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
'
|
|
266
|
-
|
|
267
|
-
|
|
311
|
+
# Only add the current module if it has content beyond just nested modules
|
|
312
|
+
# Check if there are any struct, enum, typedef, or const definitions directly in this module
|
|
313
|
+
lines = module_content.split('\n')
|
|
314
|
+
has_direct_definitions = False
|
|
315
|
+
in_nested_module = False
|
|
316
|
+
brace_level = 0
|
|
317
|
+
|
|
318
|
+
for line in lines:
|
|
319
|
+
line = line.strip()
|
|
320
|
+
if line.startswith('module ') and '{' in line:
|
|
321
|
+
in_nested_module = True
|
|
322
|
+
brace_level = 1
|
|
323
|
+
elif in_nested_module:
|
|
324
|
+
brace_level += line.count('{') - line.count('}')
|
|
325
|
+
if brace_level <= 0:
|
|
326
|
+
in_nested_module = False
|
|
327
|
+
elif not in_nested_module and re.search(r'^\s*(struct|enum|typedef|const)\s+\w+', line):
|
|
328
|
+
has_direct_definitions = True
|
|
329
|
+
break
|
|
330
|
+
|
|
331
|
+
if has_direct_definitions:
|
|
332
|
+
modules.append({
|
|
333
|
+
'name': module_name,
|
|
334
|
+
'content': module_content
|
|
335
|
+
})
|
|
336
|
+
else:
|
|
337
|
+
# No nested modules, always add this module
|
|
338
|
+
modules.append({
|
|
339
|
+
'name': module_name,
|
|
340
|
+
'content': module_content
|
|
341
|
+
})
|
|
268
342
|
|
|
269
343
|
pos = current_pos
|
|
270
344
|
else:
|
|
@@ -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.4.0](https://github.com/RobotWebTools/rclnodejs/tree/1.4.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
|
-
});
|