rclnodejs 0.33.0 → 1.1.0

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.
Files changed (77) hide show
  1. package/README.md +3 -3
  2. package/binding.gyp +25 -2
  3. package/lib/action/client.js +40 -0
  4. package/lib/action/server.js +21 -0
  5. package/lib/client.js +3 -4
  6. package/lib/context.js +8 -0
  7. package/lib/distro.js +2 -0
  8. package/lib/lifecycle.js +9 -0
  9. package/lib/logging.js +26 -9
  10. package/lib/node.js +81 -1
  11. package/lib/node_options.js +21 -1
  12. package/lib/publisher.js +27 -0
  13. package/lib/service.js +10 -3
  14. package/lib/subscription.js +8 -0
  15. package/lib/timer.js +32 -0
  16. package/lib/type_description_service.js +82 -0
  17. package/package.json +4 -4
  18. package/scripts/config.js +1 -0
  19. package/scripts/npmjs-readme.md +3 -3
  20. package/src/addon.cpp +60 -53
  21. package/src/executor.cpp +19 -10
  22. package/src/{executor.hpp → executor.h} +7 -5
  23. package/src/handle_manager.cpp +30 -56
  24. package/src/{handle_manager.hpp → handle_manager.h} +8 -7
  25. package/src/{macros.hpp → macros.h} +7 -5
  26. package/src/rcl_action_client_bindings.cpp +306 -0
  27. package/src/{rcl_action_bindings.hpp → rcl_action_client_bindings.h} +6 -11
  28. package/src/rcl_action_goal_bindings.cpp +117 -0
  29. package/src/rcl_action_goal_bindings.h +26 -0
  30. package/src/rcl_action_server_bindings.cpp +520 -0
  31. package/src/rcl_action_server_bindings.h +26 -0
  32. package/src/rcl_bindings.cpp +42 -2010
  33. package/src/{rcl_bindings.hpp → rcl_bindings.h} +5 -25
  34. package/src/rcl_client_bindings.cpp +183 -0
  35. package/src/rcl_client_bindings.h +26 -0
  36. package/src/rcl_context_bindings.cpp +156 -0
  37. package/src/rcl_context_bindings.h +26 -0
  38. package/src/rcl_graph_bindings.cpp +280 -0
  39. package/src/rcl_graph_bindings.h +26 -0
  40. package/src/rcl_guard_condition_bindings.cpp +75 -0
  41. package/src/rcl_guard_condition_bindings.h +26 -0
  42. package/src/rcl_handle.cpp +41 -57
  43. package/src/{rcl_handle.hpp → rcl_handle.h} +18 -17
  44. package/src/rcl_lifecycle_bindings.cpp +148 -114
  45. package/src/{rcl_lifecycle_bindings.hpp → rcl_lifecycle_bindings.h} +5 -7
  46. package/src/rcl_logging_bindings.cpp +96 -0
  47. package/src/rcl_logging_bindings.h +26 -0
  48. package/src/rcl_names_bindings.cpp +255 -0
  49. package/src/rcl_names_bindings.h +26 -0
  50. package/src/rcl_node_bindings.cpp +476 -0
  51. package/src/rcl_node_bindings.h +26 -0
  52. package/src/rcl_publisher_bindings.cpp +160 -0
  53. package/src/rcl_publisher_bindings.h +26 -0
  54. package/src/rcl_service_bindings.cpp +185 -0
  55. package/src/rcl_service_bindings.h +26 -0
  56. package/src/rcl_subscription_bindings.cpp +335 -0
  57. package/src/rcl_subscription_bindings.h +26 -0
  58. package/src/rcl_time_point_bindings.cpp +194 -0
  59. package/src/rcl_time_point_bindings.h +26 -0
  60. package/src/rcl_timer_bindings.cpp +237 -0
  61. package/src/rcl_timer_bindings.h +26 -0
  62. package/src/rcl_type_description_service_bindings.cpp +79 -0
  63. package/src/rcl_type_description_service_bindings.h +27 -0
  64. package/src/rcl_utilities.cpp +166 -1
  65. package/src/{rcl_utilities.hpp → rcl_utilities.h} +21 -3
  66. package/src/shadow_node.cpp +56 -75
  67. package/src/{shadow_node.hpp → shadow_node.h} +18 -17
  68. package/types/action_client.d.ts +18 -0
  69. package/types/action_server.d.ts +12 -0
  70. package/types/context.d.ts +6 -0
  71. package/types/lifecycle.d.ts +7 -0
  72. package/types/node.d.ts +69 -0
  73. package/types/publisher.d.ts +23 -0
  74. package/types/service.d.ts +6 -0
  75. package/types/subscription.d.ts +6 -0
  76. package/types/timer.d.ts +18 -0
  77. package/src/rcl_action_bindings.cpp +0 -826
package/README.md CHANGED
@@ -43,9 +43,9 @@ npm i rclnodejs@x.y.z
43
43
 
44
44
  #### RCLNODEJS - ROS 2 Version Compatibility
45
45
 
46
- | RCLNODEJS Version | Compatible ROS 2 LTS |
47
- | :------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------: |
48
- | latest version (currently [v0.33.0](https://github.com/RobotWebTools/rclnodejs/tree/0.33.0)) | [Humble](https://github.com/RobotWebTools/rclnodejs/tree/humble-hawksbill)<br>[Jazzy](https://github.com/RobotWebTools/rclnodejs/tree/jazzy) |
46
+ | RCLNODEJS Version | Compatible ROS 2 LTS |
47
+ | :----------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
48
+ | latest version (currently [v1.1.0](https://github.com/RobotWebTools/rclnodejs/tree/1.1.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
49
 
50
50
  ## Documentation
51
51
 
package/binding.gyp CHANGED
@@ -21,17 +21,31 @@
21
21
  './src/addon.cpp',
22
22
  './src/executor.cpp',
23
23
  './src/handle_manager.cpp',
24
- './src/rcl_action_bindings.cpp',
24
+ './src/rcl_action_client_bindings.cpp',
25
+ './src/rcl_action_goal_bindings.cpp',
26
+ './src/rcl_action_server_bindings.cpp',
25
27
  './src/rcl_bindings.cpp',
28
+ './src/rcl_client_bindings.cpp',
29
+ './src/rcl_context_bindings.cpp',
30
+ './src/rcl_graph_bindings.cpp',
31
+ './src/rcl_guard_condition_bindings.cpp',
26
32
  './src/rcl_handle.cpp',
27
33
  './src/rcl_lifecycle_bindings.cpp',
34
+ './src/rcl_logging_bindings.cpp',
35
+ './src/rcl_names_bindings.cpp',
36
+ './src/rcl_node_bindings.cpp',
37
+ './src/rcl_publisher_bindings.cpp',
38
+ './src/rcl_service_bindings.cpp',
39
+ './src/rcl_subscription_bindings.cpp',
40
+ './src/rcl_time_point_bindings.cpp',
41
+ './src/rcl_timer_bindings.cpp',
28
42
  './src/rcl_utilities.cpp',
29
43
  './src/shadow_node.cpp',
30
44
  ],
31
45
  'include_dirs': [
32
46
  '.',
33
- "<!(node -e \"require('nan')\")",
34
47
  '<(ros_include_root)',
48
+ "<!@(node -p \"require('node-addon-api').include\")",
35
49
  ],
36
50
  'cflags!': [
37
51
  '-fno-exceptions'
@@ -51,6 +65,7 @@
51
65
  '-lrcl_lifecycle',
52
66
  '-lrcutils',
53
67
  '-lrcl_yaml_param_parser',
68
+ '-lrcpputils',
54
69
  '-lrmw',
55
70
  '-lrosidl_runtime_c',
56
71
  ],
@@ -151,6 +166,14 @@
151
166
  ]
152
167
  }
153
168
  ],
169
+ [
170
+ # After Humble, e.g., Jazzy, Kilted.
171
+ 'ros_version > 2205', {
172
+ 'sources': [
173
+ './src/rcl_type_description_service_bindings.cpp',
174
+ ]
175
+ }
176
+ ],
154
177
  [
155
178
  'runtime=="electron"', {
156
179
  "defines": ["NODE_RUNTIME_ELECTRON=1"]
@@ -19,6 +19,7 @@ const ActionInterfaces = require('./interfaces.js');
19
19
  const ActionUuid = require('./uuid.js');
20
20
  const ClientGoalHandle = require('./client_goal_handle.js');
21
21
  const Deferred = require('./deferred.js');
22
+ const DistroUtils = require('../distro.js');
22
23
  const Entity = require('../entity.js');
23
24
  const loader = require('../interface_loader.js');
24
25
  const QoS = require('../qos.js');
@@ -371,6 +372,45 @@ class ActionClient extends Entity {
371
372
 
372
373
  this._node._destroyEntity(this, this._node._actionClients);
373
374
  }
375
+
376
+ /**
377
+ * Get the number of wait set entities that make up an action entity.
378
+ * @return {object} - An object containing the number of various entities.
379
+ * @property {number} subscriptionsNumber - The number of subscriptions.
380
+ * @property {number} guardConditionsNumber - The number of guard conditions.
381
+ * @property {number} timersNumber - The number of timers.
382
+ * @property {number} clientsNumber - The number of clients.
383
+ * @property {number} servicesNumber - The number of services.
384
+ */
385
+ getNumEntities() {
386
+ return rclnodejs.getNumEntities(this.handle);
387
+ }
388
+
389
+ /**
390
+ * Configure introspection.
391
+ * @param {Clock} clock - Clock to use for service event timestamps
392
+ * @param {QoS} qos - QoSProfile for the service event publisher
393
+ * @param {ServiceIntrospectionState} introspectionState - State to set introspection to
394
+ */
395
+ configureIntrospection(clock, qos, introspectionState) {
396
+ if (DistroUtils.getDistroId() <= DistroUtils.getDistroId('jazzy')) {
397
+ console.warn(
398
+ 'Configure action client introspection is not supported by this version of ROS 2'
399
+ );
400
+ return;
401
+ }
402
+
403
+ let type = this.typeClass.type();
404
+ rclnodejs.configureActionClientIntrospection(
405
+ this.handle,
406
+ this._node.handle,
407
+ clock.handle,
408
+ type.interfaceName,
409
+ type.pkgName,
410
+ qos,
411
+ introspectionState
412
+ );
413
+ }
374
414
  }
375
415
 
376
416
  module.exports = ActionClient;
@@ -17,6 +17,7 @@
17
17
  const rclnodejs = require('bindings')('rclnodejs');
18
18
  const ActionInterfaces = require('./interfaces.js');
19
19
  const ActionUuid = require('./uuid.js');
20
+ const DistroUtils = require('../distro.js');
20
21
  const Entity = require('../entity.js');
21
22
  const { CancelResponse, GoalEvent, GoalResponse } = require('./response.js');
22
23
  const loader = require('../interface_loader.js');
@@ -454,6 +455,26 @@ class ActionServer extends Entity {
454
455
 
455
456
  this._node._destroyEntity(this, this._node._actionServers);
456
457
  }
458
+
459
+ configureIntrospection(clock, qos, introspectionState) {
460
+ if (DistroUtils.getDistroId() <= DistroUtils.getDistroId('jazzy')) {
461
+ console.warn(
462
+ 'Configure action server introspection is not supported by this version of ROS 2'
463
+ );
464
+ return;
465
+ }
466
+
467
+ let type = this.typeClass.type();
468
+ rclnodejs.configureActionServerIntrospection(
469
+ this.handle,
470
+ this._node.handle,
471
+ clock.handle,
472
+ type.interfaceName,
473
+ type.pkgName,
474
+ qos,
475
+ introspectionState
476
+ );
477
+ }
457
478
  }
458
479
 
459
480
  module.exports = ActionServer;
package/lib/client.js CHANGED
@@ -141,21 +141,20 @@ class Client extends Entity {
141
141
  configureIntrospection(clock, qos, introspectionState) {
142
142
  if (DistroUtils.getDistroId() <= DistroUtils.getDistroId('humble')) {
143
143
  console.warn(
144
- 'Service introspection is not supported by this versionof ROS 2'
144
+ 'Service introspection is not supported by this version of ROS 2'
145
145
  );
146
146
  return;
147
147
  }
148
148
 
149
149
  let type = this.typeClass.type();
150
- rclnodejs.configureServiceIntrospection(
150
+ rclnodejs.configureClientIntrospection(
151
151
  this.handle,
152
152
  this._nodeHandle,
153
153
  clock.handle,
154
154
  type.interfaceName,
155
155
  type.pkgName,
156
156
  qos,
157
- introspectionState,
158
- false
157
+ introspectionState
159
158
  );
160
159
  }
161
160
  }
package/lib/context.js CHANGED
@@ -219,6 +219,14 @@ class Context {
219
219
  }
220
220
  return defaultContext;
221
221
  }
222
+
223
+ /**
224
+ * Get the domain ID of this context.
225
+ * @returns {Number} domain ID of this context
226
+ */
227
+ get domainId() {
228
+ return rclnodejs.getDomainId(this.handle);
229
+ }
222
230
  }
223
231
 
224
232
  Context._instances = [];
package/lib/distro.js CHANGED
@@ -25,6 +25,7 @@ const DistroId = {
25
25
  HUMBLE: 2205,
26
26
  IRON: 2305,
27
27
  JAZZY: 2405,
28
+ KILTED: 2505,
28
29
  ROLLING: 5000,
29
30
  };
30
31
 
@@ -35,6 +36,7 @@ DistroNameIdMap.set('galactic', DistroId.GALACTIC);
35
36
  DistroNameIdMap.set('humble', DistroId.HUMBLE);
36
37
  DistroNameIdMap.set('iron', DistroId.IRON);
37
38
  DistroNameIdMap.set('jazzy', DistroId.JAZZY);
39
+ DistroNameIdMap.set('kilted', DistroId.KILTED);
38
40
  DistroNameIdMap.set('rolling', DistroId.ROLLING);
39
41
 
40
42
  const DistroUtils = {
package/lib/lifecycle.js CHANGED
@@ -591,6 +591,15 @@ class LifecycleNode extends Node {
591
591
  return this._changeState(SHUTDOWN_TRANSITION_LABEL, callbackReturnValue);
592
592
  }
593
593
 
594
+ /**
595
+ * Check if state machine is initialized.
596
+ *
597
+ * @returns {boolean} true if the state machine is initialized; otherwise false.
598
+ */
599
+ get isInitialized() {
600
+ return rclnodejs.isInitialized(this._stateMachineHandle);
601
+ }
602
+
594
603
  /**
595
604
  * The GetState service handler.
596
605
  * @param {Object} request - The GetState service request.
package/lib/logging.js CHANGED
@@ -39,14 +39,31 @@ let LoggingSeverity = {
39
39
 
40
40
  class Caller {
41
41
  constructor() {
42
- this._info = {};
43
- let frame = new Error().stack.split('\n').slice(4, 5)[0];
44
- let results = frame.match(/at\s+(.*)\s+\((.*):(\d*):(\d*)\)/i);
45
-
46
- if (results && results.length === 5) {
47
- this._info['functionName'] = results[1];
48
- this._info['lineNumber'] = results[3];
49
- this._info['fileName'] = path.basename(results[2]);
42
+ this._info = {
43
+ functionName: 'unknown',
44
+ fileName: 'unknown',
45
+ lineNumber: 'unknown',
46
+ };
47
+
48
+ const stackLines = new Error().stack.split('\n');
49
+
50
+ // Adjust the index (usually 3 or 4) to correctly point to the caller frame.
51
+ const callerFrame = stackLines[4] || stackLines[3];
52
+ // Match both named and anonymous function stack frames.
53
+ const frameRegex = /^\s*at\s+(?:(.+)\s+\()?(.+):(\d+):(\d+)\)?$/;
54
+ const match = callerFrame.match(frameRegex);
55
+ if (match && match.length === 5) {
56
+ this._info.functionName = match[1] || '(anonymous)';
57
+ this._info.fileName = path.basename(match[2]);
58
+ this._info.lineNumber = match[3];
59
+ } else {
60
+ // Handle anonymous functions or different stack formats.
61
+ const altMatch = callerFrame.match(/at\s+(.*):(\d+):(\d+)/i);
62
+ if (altMatch && altMatch.length >= 4) {
63
+ this._info.functionName = '(anonymous)';
64
+ this._info.fileName = path.basename(altMatch[1]);
65
+ this._info.lineNumber = altMatch[2];
66
+ }
50
67
  }
51
68
  }
52
69
 
@@ -156,7 +173,7 @@ class Logging {
156
173
  severity,
157
174
  message,
158
175
  caller.functionName,
159
- caller.lineNumber,
176
+ parseInt(caller.lineNumber, 10),
160
177
  caller.fileName
161
178
  );
162
179
  }
package/lib/node.js CHANGED
@@ -21,6 +21,7 @@ const Client = require('./client.js');
21
21
  const Clock = require('./clock.js');
22
22
  const Context = require('./context.js');
23
23
  const debug = require('debug')('rclnodejs:node');
24
+ const DistroUtils = require('./distro.js');
24
25
  const GuardCondition = require('./guard_condition.js');
25
26
  const loader = require('./interface_loader.js');
26
27
  const Logging = require('./logging.js');
@@ -38,6 +39,7 @@ const Service = require('./service.js');
38
39
  const Subscription = require('./subscription.js');
39
40
  const TimeSource = require('./time_source.js');
40
41
  const Timer = require('./timer.js');
42
+ const TypeDescriptionService = require('./type_description_service.js');
41
43
  const Entity = require('./entity.js');
42
44
 
43
45
  // Parameter event publisher constants
@@ -100,6 +102,7 @@ class Node extends rclnodejs.ShadowNode {
100
102
  this._parameterDescriptors = new Map();
101
103
  this._parameters = new Map();
102
104
  this._parameterService = null;
105
+ this._typeDescriptionService = null;
103
106
  this._parameterEventPublisher = null;
104
107
  this._setParametersCallbacks = [];
105
108
  this._logger = new Logging(rclnodejs.getNodeLoggerName(this.handle));
@@ -146,6 +149,14 @@ class Node extends rclnodejs.ShadowNode {
146
149
  this._parameterService = new ParameterService(this);
147
150
  this._parameterService.start();
148
151
  }
152
+
153
+ if (
154
+ DistroUtils.getDistroId() >= DistroUtils.getDistroId('jazzy') &&
155
+ options.startTypeDescriptionService
156
+ ) {
157
+ this._typeDescriptionService = new TypeDescriptionService(this);
158
+ this._typeDescriptionService.start();
159
+ }
149
160
  }
150
161
 
151
162
  execute(handles) {
@@ -1013,6 +1024,32 @@ class Node extends rclnodejs.ShadowNode {
1013
1024
  return rclnodejs.getServiceNamesAndTypes(this.handle);
1014
1025
  }
1015
1026
 
1027
+ /**
1028
+ * Get a list of publishers on a given topic.
1029
+ * @param {string} topic - the topic name to get the publishers for.
1030
+ * @param {boolean} noDemangle - if `true`, `topic_name` needs to be a valid middleware topic name,
1031
+ * otherwise it should be a valid ROS topic name.
1032
+ * @returns {Array} - list of publishers
1033
+ */
1034
+ getPublishersInfoByTopic(topic, noDemangle) {
1035
+ return rclnodejs.getPublishersInfoByTopic(this.handle, topic, noDemangle);
1036
+ }
1037
+
1038
+ /**
1039
+ * Get a list of subscriptions on a given topic.
1040
+ * @param {string} topic - the topic name to get the subscriptions for.
1041
+ * @param {boolean} noDemangle - if `true`, `topic_name` needs to be a valid middleware topic name,
1042
+ * otherwise it should be a valid ROS topic name.
1043
+ * @returns {Array} - list of subscriptions
1044
+ */
1045
+ getSubscriptionsInfoByTopic(topic, noDemangle) {
1046
+ return rclnodejs.getSubscriptionsInfoByTopic(
1047
+ this.handle,
1048
+ topic,
1049
+ noDemangle
1050
+ );
1051
+ }
1052
+
1016
1053
  /**
1017
1054
  * Get the list of nodes discovered by the provided node.
1018
1055
  * @return {Array<string>} - An array of the names.
@@ -1026,7 +1063,15 @@ class Node extends rclnodejs.ShadowNode {
1026
1063
  * @return {Array<{name: string, namespace: string}>} An array of the names and namespaces.
1027
1064
  */
1028
1065
  getNodeNamesAndNamespaces() {
1029
- return rclnodejs.getNodeNames(this.handle);
1066
+ return rclnodejs.getNodeNames(this.handle, /*getEnclaves=*/ false);
1067
+ }
1068
+
1069
+ /**
1070
+ * Get the list of nodes and their namespaces with enclaves discovered by the provided node.
1071
+ * @return {Array<{name: string, namespace: string, enclave: string}>} An array of the names, namespaces and enclaves.
1072
+ */
1073
+ getNodeNamesAndNamespacesWithEnclaves() {
1074
+ return rclnodejs.getNodeNames(this.handle, /*getEnclaves=*/ true);
1030
1075
  }
1031
1076
 
1032
1077
  /**
@@ -1061,6 +1106,32 @@ class Node extends rclnodejs.ShadowNode {
1061
1106
  return rclnodejs.countSubscribers(this.handle, expandedTopic);
1062
1107
  }
1063
1108
 
1109
+ /**
1110
+ * Get the number of clients on a given service name.
1111
+ * @param {string} serviceName - the service name
1112
+ * @returns {Number}
1113
+ */
1114
+ countClients(serviceName) {
1115
+ if (DistroUtils.getDistroId() <= DistroUtils.getDistroId('humble')) {
1116
+ console.warn('countClients is not supported by this version of ROS 2');
1117
+ return null;
1118
+ }
1119
+ return rclnodejs.countClients(this.handle, serviceName);
1120
+ }
1121
+
1122
+ /**
1123
+ * Get the number of services on a given service name.
1124
+ * @param {string} serviceName - the service name
1125
+ * @returns {Number}
1126
+ */
1127
+ countServices(serviceName) {
1128
+ if (DistroUtils.getDistroId() <= DistroUtils.getDistroId('humble')) {
1129
+ console.warn('countServices is not supported by this version of ROS 2');
1130
+ return null;
1131
+ }
1132
+ return rclnodejs.countServices(this.handle, serviceName);
1133
+ }
1134
+
1064
1135
  /**
1065
1136
  * Get the list of parameter-overrides found on the commandline and
1066
1137
  * in the NodeOptions.parameter_overrides property.
@@ -1557,6 +1628,15 @@ class Node extends rclnodejs.ShadowNode {
1557
1628
  }
1558
1629
  }
1559
1630
 
1631
+ /**
1632
+ * Get the fully qualified name of the node.
1633
+ *
1634
+ * @returns {string} - String containing the fully qualified name of the node.
1635
+ */
1636
+ getFullyQualifiedName() {
1637
+ return rclnodejs.getFullyQualifiedName(this.handle);
1638
+ }
1639
+
1560
1640
  // returns on 1st error or result {successful, reason}
1561
1641
  _validateParameters(parameters = [], declareParameterMode = false) {
1562
1642
  for (const parameter of parameters) {
@@ -26,16 +26,19 @@ class NodeOptions {
26
26
  * @param {boolean} [startParameterServices=true]
27
27
  * @param {array} [parameterOverrides=[]]
28
28
  * @param {boolean} [automaticallyDeclareParametersFromOverrides=false]
29
+ * @param {boolean} [startTypeDescriptionService=true]
29
30
  */
30
31
  constructor(
31
32
  startParameterServices = true,
32
33
  parameterOverrides = [],
33
- automaticallyDeclareParametersFromOverrides = false
34
+ automaticallyDeclareParametersFromOverrides = false,
35
+ startTypeDescriptionService = true
34
36
  ) {
35
37
  this._startParameterServices = startParameterServices;
36
38
  this._parameterOverrides = parameterOverrides;
37
39
  this._automaticallyDeclareParametersFromOverrides =
38
40
  automaticallyDeclareParametersFromOverrides;
41
+ this._startTypeDescriptionService = startTypeDescriptionService;
39
42
  }
40
43
 
41
44
  /**
@@ -105,6 +108,23 @@ class NodeOptions {
105
108
  this._automaticallyDeclareParametersFromOverrides = declareParamsFlag;
106
109
  }
107
110
 
111
+ /**
112
+ * Get the startTypeDescriptionService option, only available for ROS2 > Humble.
113
+ * Default value = true;
114
+ * @returns {boolean} - true if the type description service is enabled.
115
+ */
116
+ get startTypeDescriptionService() {
117
+ return this._startTypeDescriptionService;
118
+ }
119
+
120
+ /**
121
+ * Set startTypeDescriptionService, only available for ROS2 > Humble
122
+ * @param {boolean} willStartTypeDescriptionService
123
+ */
124
+ set startTypeDescriptionService(willStartTypeDescriptionService) {
125
+ this._startTypeDescriptionService = willStartTypeDescriptionService;
126
+ }
127
+
108
128
  /**
109
129
  * Return an instance configured with default options.
110
130
  * @returns {NodeOptions} - An instance with default values.
package/lib/publisher.js CHANGED
@@ -72,6 +72,33 @@ class Publisher extends Entity {
72
72
  );
73
73
  return new Publisher(handle, typeClass, topic, options);
74
74
  }
75
+
76
+ /**
77
+ * Get the number of subscriptions to this publisher.
78
+ * @returns {number} The number of subscriptions
79
+ */
80
+ get subscriptionCount() {
81
+ return rclnodejs.getSubscriptionCount(this._handle);
82
+ }
83
+
84
+ /**
85
+ * Wait until all published message data is acknowledged or until the specified timeout elapses
86
+ *
87
+ * If the timeout is negative then this function will block indefinitely until all published
88
+ * message data is acknowledged.
89
+ * If the timeout is 0 then it will check if all published message has been acknowledged without
90
+ * waiting.
91
+ * If the timeout is greater than 0 then it will return after that period of time has elapsed or
92
+ * all published message data is acknowledged.
93
+ *
94
+ * Raises an error if failed, such as the middleware not supporting this feature.
95
+ *
96
+ * @param {timeout} timeout - The duration to wait for all published message data to be acknowledged in nanoseconds.
97
+ * @return {boolean} `true` if all published message data is acknowledged before the timeout, otherwise `false`.
98
+ */
99
+ waitForAllAcked(timeout) {
100
+ return rclnodejs.waitForAllAcked(this._handle, timeout);
101
+ }
75
102
  }
76
103
 
77
104
  module.exports = Publisher;
package/lib/service.js CHANGED
@@ -125,7 +125,7 @@ class Service extends Entity {
125
125
  configureIntrospection(clock, qos, introspectionState) {
126
126
  if (DistroUtils.getDistroId() <= DistroUtils.getDistroId('humble')) {
127
127
  console.warn(
128
- 'Service introspection is not supported by this versionof ROS 2'
128
+ 'Service introspection is not supported by this version of ROS 2'
129
129
  );
130
130
  return;
131
131
  }
@@ -138,10 +138,17 @@ class Service extends Entity {
138
138
  type.interfaceName,
139
139
  type.pkgName,
140
140
  qos,
141
- introspectionState,
142
- true
141
+ introspectionState
143
142
  );
144
143
  }
144
+
145
+ /**
146
+ * Get the options of this service.
147
+ * @return {object} The options of this service.
148
+ */
149
+ getOptions() {
150
+ return rclnodejs.getOptions(this._handle);
151
+ }
145
152
  }
146
153
 
147
154
  module.exports = Service;
@@ -116,6 +116,14 @@ class Subscription extends Entity {
116
116
  ? rclnodejs.clearContentFilter(this.handle)
117
117
  : true;
118
118
  }
119
+
120
+ /**
121
+ * Get the number of publishers to this subscription.
122
+ * @returns {number} The number of publishers
123
+ */
124
+ get publisherCount() {
125
+ return rclnodejs.getPublisherCount(this._handle);
126
+ }
119
127
  }
120
128
 
121
129
  module.exports = Subscription;
package/lib/timer.js CHANGED
@@ -15,6 +15,7 @@
15
15
  'use strict';
16
16
 
17
17
  const rclnodejs = require('bindings')('rclnodejs');
18
+ const DistroUtils = require('./distro.js');
18
19
 
19
20
  /**
20
21
  * @class - Class representing a Timer in ROS
@@ -86,6 +87,37 @@ class Timer {
86
87
  timeUntilNextCall() {
87
88
  return rclnodejs.timerGetTimeUntilNextCall(this._handle);
88
89
  }
90
+
91
+ /**
92
+ * Change the timer period.
93
+ * @param {bigint} period - The new period in nanoseconds.
94
+ * @return {undefined}
95
+ */
96
+ changeTimerPeriod(period) {
97
+ rclnodejs.changeTimerPeriod(this._handle, period);
98
+ }
99
+
100
+ /**
101
+ * Get the timer period.
102
+ * @return {bigint} - The period in nanoseconds.
103
+ */
104
+ get timerPeriod() {
105
+ return rclnodejs.getTimerPeriod(this._handle);
106
+ }
107
+
108
+ /**
109
+ * Call a timer and starts counting again, retrieves actual and expected call time.
110
+ * @return {object} - The timer information.
111
+ */
112
+ callTimerWithInfo() {
113
+ if (DistroUtils.getDistroId() <= DistroUtils.getDistroId('humble')) {
114
+ console.warn(
115
+ 'callTimerWithInfo is not supported by this version of ROS 2'
116
+ );
117
+ return;
118
+ }
119
+ return rclnodejs.callTimerWithInfo(this._handle);
120
+ }
89
121
  }
90
122
 
91
123
  module.exports = Timer;
@@ -0,0 +1,82 @@
1
+ // Copyright (c) 2025, The Robot Web Tools Contributors
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 loader = require('./interface_loader.js');
18
+ const rclnodejs = require('bindings')('rclnodejs');
19
+ const Service = require('./service.js');
20
+
21
+ // This class is used to create a TypeDescriptionService which can be used to
22
+ // retrieve information about types used by the node’s publishers, subscribers,
23
+ // services or actions.
24
+ class TypeDescriptionService {
25
+ constructor(node) {
26
+ this._node = node;
27
+ this._serviceName = this._node.name() + '/get_type_description';
28
+ this._typeDescriptionServiceHandle = rclnodejs.initTypeDescriptionService(
29
+ this._node.handle
30
+ );
31
+ this._typeClass = loader.loadInterface(
32
+ 'type_description_interfaces/srv/GetTypeDescription'
33
+ );
34
+ this._typeDescriptionService = null;
35
+ }
36
+
37
+ start() {
38
+ if (this._typeDescriptionService) {
39
+ return;
40
+ }
41
+
42
+ this._typeDescriptionService = new Service(
43
+ this._node.handle,
44
+ this._typeDescriptionServiceHandle,
45
+ this._serviceName,
46
+ this._typeClass,
47
+ this._node._validateOptions(undefined),
48
+ (request, response) => {
49
+ const responseToBeSent = new this._typeClass.Response();
50
+ const requestReceived = new this._typeClass.Request(request);
51
+ rclnodejs.handleRequest(
52
+ this._node.handle,
53
+ requestReceived.serialize(),
54
+ responseToBeSent.serialize()
55
+ );
56
+ responseToBeSent.deserialize(responseToBeSent.refObject);
57
+ rclnodejs.sendResponse(
58
+ this._typeDescriptionServiceHandle,
59
+ responseToBeSent.serialize(),
60
+ response._header
61
+ );
62
+ return null;
63
+ }
64
+ );
65
+ this._node._services.push(this._typeDescriptionService);
66
+ this._node.syncHandles();
67
+ }
68
+
69
+ /**
70
+ * Get the node this
71
+ * @return {Node} - The supported node.
72
+ */
73
+ get node() {
74
+ return this._node;
75
+ }
76
+
77
+ static toTypeHash(topicTypeHash) {
78
+ return `RIHS0${topicTypeHash.version}_${topicTypeHash.value.toString('hex')}`;
79
+ }
80
+ }
81
+
82
+ module.exports = TypeDescriptionService;