rclnodejs 1.6.0 → 1.8.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.
- package/binding.gyp +2 -0
- package/index.js +152 -0
- package/lib/action/client.js +109 -10
- package/lib/action/deferred.js +8 -2
- package/lib/action/server.js +10 -1
- package/lib/action/uuid.js +4 -1
- package/lib/client.js +218 -4
- package/lib/clock.js +182 -1
- package/lib/clock_change.js +49 -0
- package/lib/clock_event.js +88 -0
- package/lib/context.js +12 -2
- package/lib/duration.js +37 -12
- package/lib/errors.js +621 -0
- package/lib/event_handler.js +21 -4
- package/lib/interface_loader.js +52 -12
- package/lib/lifecycle.js +8 -2
- package/lib/logging.js +90 -3
- package/lib/message_introspector.js +123 -0
- package/lib/message_serialization.js +10 -2
- package/lib/message_validation.js +512 -0
- package/lib/native_loader.js +9 -4
- package/lib/node.js +403 -50
- package/lib/node_options.js +40 -1
- package/lib/observable_subscription.js +105 -0
- package/lib/parameter.js +172 -35
- package/lib/parameter_client.js +506 -0
- package/lib/parameter_watcher.js +309 -0
- package/lib/publisher.js +56 -1
- package/lib/qos.js +79 -5
- package/lib/rate.js +6 -1
- package/lib/serialization.js +7 -2
- package/lib/subscription.js +8 -0
- package/lib/time.js +136 -21
- package/lib/time_source.js +13 -4
- package/lib/timer.js +42 -0
- package/lib/utils.js +27 -1
- package/lib/validator.js +74 -19
- package/package.json +4 -2
- package/prebuilds/linux-arm64/humble-jammy-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-arm64/jazzy-noble-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-arm64/kilted-noble-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/humble-jammy-x64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/jazzy-noble-x64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/kilted-noble-x64-rclnodejs.node +0 -0
- package/rosidl_gen/message_translator.js +0 -61
- package/scripts/config.js +1 -0
- package/src/addon.cpp +2 -0
- package/src/clock_event.cpp +268 -0
- package/src/clock_event.hpp +62 -0
- package/src/macros.h +2 -4
- package/src/rcl_action_server_bindings.cpp +21 -3
- package/src/rcl_bindings.cpp +59 -0
- package/src/rcl_context_bindings.cpp +5 -0
- package/src/rcl_graph_bindings.cpp +73 -0
- package/src/rcl_logging_bindings.cpp +158 -0
- package/src/rcl_node_bindings.cpp +14 -2
- package/src/rcl_publisher_bindings.cpp +12 -0
- package/src/rcl_service_bindings.cpp +7 -6
- package/src/rcl_subscription_bindings.cpp +51 -14
- package/src/rcl_time_point_bindings.cpp +135 -0
- package/src/rcl_timer_bindings.cpp +140 -0
- package/src/rcl_utilities.cpp +103 -2
- package/src/rcl_utilities.h +7 -1
- package/types/action_client.d.ts +27 -2
- package/types/base.d.ts +6 -0
- package/types/client.d.ts +65 -1
- package/types/clock.d.ts +86 -0
- package/types/clock_change.d.ts +27 -0
- package/types/clock_event.d.ts +51 -0
- package/types/errors.d.ts +496 -0
- package/types/index.d.ts +10 -0
- package/types/logging.d.ts +32 -0
- package/types/message_introspector.d.ts +75 -0
- package/types/message_validation.d.ts +183 -0
- package/types/node.d.ts +107 -0
- package/types/node_options.d.ts +13 -0
- package/types/observable_subscription.d.ts +39 -0
- package/types/parameter_client.d.ts +252 -0
- package/types/parameter_watcher.d.ts +104 -0
- package/types/publisher.d.ts +28 -1
- package/types/qos.d.ts +18 -0
- package/types/subscription.d.ts +6 -0
- package/types/timer.d.ts +18 -0
- package/types/validator.d.ts +86 -0
package/lib/node.js
CHANGED
|
@@ -32,12 +32,20 @@ const {
|
|
|
32
32
|
ParameterDescriptor,
|
|
33
33
|
} = require('./parameter.js');
|
|
34
34
|
const { isValidSerializationMode } = require('./message_serialization.js');
|
|
35
|
+
const {
|
|
36
|
+
TypeValidationError,
|
|
37
|
+
RangeValidationError,
|
|
38
|
+
ValidationError,
|
|
39
|
+
} = require('./errors.js');
|
|
35
40
|
const ParameterService = require('./parameter_service.js');
|
|
41
|
+
const ParameterClient = require('./parameter_client.js');
|
|
42
|
+
const ParameterWatcher = require('./parameter_watcher.js');
|
|
36
43
|
const Publisher = require('./publisher.js');
|
|
37
44
|
const QoS = require('./qos.js');
|
|
38
45
|
const Rates = require('./rate.js');
|
|
39
46
|
const Service = require('./service.js');
|
|
40
47
|
const Subscription = require('./subscription.js');
|
|
48
|
+
const ObservableSubscription = require('./observable_subscription.js');
|
|
41
49
|
const TimeSource = require('./time_source.js');
|
|
42
50
|
const Timer = require('./timer.js');
|
|
43
51
|
const TypeDescriptionService = require('./type_description_service.js');
|
|
@@ -74,8 +82,11 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
74
82
|
) {
|
|
75
83
|
super();
|
|
76
84
|
|
|
77
|
-
if (typeof nodeName !== 'string'
|
|
78
|
-
throw new
|
|
85
|
+
if (typeof nodeName !== 'string') {
|
|
86
|
+
throw new TypeValidationError('nodeName', nodeName, 'string');
|
|
87
|
+
}
|
|
88
|
+
if (typeof namespace !== 'string') {
|
|
89
|
+
throw new TypeValidationError('namespace', namespace, 'string');
|
|
79
90
|
}
|
|
80
91
|
|
|
81
92
|
this._init(nodeName, namespace, options, context, args, useGlobalArguments);
|
|
@@ -92,7 +103,8 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
92
103
|
namespace,
|
|
93
104
|
context.handle,
|
|
94
105
|
args,
|
|
95
|
-
useGlobalArguments
|
|
106
|
+
useGlobalArguments,
|
|
107
|
+
options.rosoutQos
|
|
96
108
|
);
|
|
97
109
|
Object.defineProperty(this, 'handle', {
|
|
98
110
|
configurable: false,
|
|
@@ -111,6 +123,8 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
111
123
|
this._events = [];
|
|
112
124
|
this._actionClients = [];
|
|
113
125
|
this._actionServers = [];
|
|
126
|
+
this._parameterClients = [];
|
|
127
|
+
this._parameterWatchers = [];
|
|
114
128
|
this._rateTimerServer = null;
|
|
115
129
|
this._parameterDescriptors = new Map();
|
|
116
130
|
this._parameters = new Map();
|
|
@@ -120,6 +134,11 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
120
134
|
this._setParametersCallbacks = [];
|
|
121
135
|
this._logger = new Logging(rclnodejs.getNodeLoggerName(this.handle));
|
|
122
136
|
this._spinning = false;
|
|
137
|
+
this._enableRosout = options.enableRosout;
|
|
138
|
+
|
|
139
|
+
if (this._enableRosout) {
|
|
140
|
+
rclnodejs.initRosoutPublisherForNode(this.handle);
|
|
141
|
+
}
|
|
123
142
|
|
|
124
143
|
this._parameterEventPublisher = this.createPublisher(
|
|
125
144
|
PARAMETER_EVENT_MSG_TYPE,
|
|
@@ -133,8 +152,13 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
133
152
|
if (options.parameterOverrides.length > 0) {
|
|
134
153
|
for (const parameter of options.parameterOverrides) {
|
|
135
154
|
if ((!parameter) instanceof Parameter) {
|
|
136
|
-
throw new
|
|
137
|
-
'
|
|
155
|
+
throw new TypeValidationError(
|
|
156
|
+
'parameterOverride',
|
|
157
|
+
parameter,
|
|
158
|
+
'Parameter instance',
|
|
159
|
+
{
|
|
160
|
+
nodeName: name,
|
|
161
|
+
}
|
|
138
162
|
);
|
|
139
163
|
}
|
|
140
164
|
this._parameterOverrides.set(parameter.name, parameter);
|
|
@@ -514,7 +538,9 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
514
538
|
options !== undefined &&
|
|
515
539
|
(options === null || typeof options !== 'object')
|
|
516
540
|
) {
|
|
517
|
-
throw new
|
|
541
|
+
throw new TypeValidationError('options', options, 'object', {
|
|
542
|
+
nodeName: this.name(),
|
|
543
|
+
});
|
|
518
544
|
}
|
|
519
545
|
|
|
520
546
|
if (options === undefined) {
|
|
@@ -536,8 +562,15 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
536
562
|
if (options.serializationMode === undefined) {
|
|
537
563
|
options = Object.assign(options, { serializationMode: 'default' });
|
|
538
564
|
} else if (!isValidSerializationMode(options.serializationMode)) {
|
|
539
|
-
throw new
|
|
540
|
-
`Invalid serializationMode: ${options.serializationMode}. Valid modes are: 'default', 'plain', 'json'
|
|
565
|
+
throw new ValidationError(
|
|
566
|
+
`Invalid serializationMode: ${options.serializationMode}. Valid modes are: 'default', 'plain', 'json'`,
|
|
567
|
+
{
|
|
568
|
+
code: 'INVALID_SERIALIZATION_MODE',
|
|
569
|
+
argumentName: 'serializationMode',
|
|
570
|
+
providedValue: options.serializationMode,
|
|
571
|
+
expectedType: "'default' | 'plain' | 'json'",
|
|
572
|
+
nodeName: this.name(),
|
|
573
|
+
}
|
|
541
574
|
);
|
|
542
575
|
}
|
|
543
576
|
|
|
@@ -558,8 +591,15 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
558
591
|
clock = arguments[3];
|
|
559
592
|
}
|
|
560
593
|
|
|
561
|
-
if (typeof period !== 'bigint'
|
|
562
|
-
throw new
|
|
594
|
+
if (typeof period !== 'bigint') {
|
|
595
|
+
throw new TypeValidationError('period', period, 'bigint', {
|
|
596
|
+
nodeName: this.name(),
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
if (typeof callback !== 'function') {
|
|
600
|
+
throw new TypeValidationError('callback', callback, 'function', {
|
|
601
|
+
nodeName: this.name(),
|
|
602
|
+
});
|
|
563
603
|
}
|
|
564
604
|
|
|
565
605
|
const timerClock = clock || this._clock;
|
|
@@ -584,13 +624,20 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
584
624
|
*/
|
|
585
625
|
async createRate(hz = 1) {
|
|
586
626
|
if (typeof hz !== 'number') {
|
|
587
|
-
throw new
|
|
627
|
+
throw new TypeValidationError('hz', hz, 'number', {
|
|
628
|
+
nodeName: this.name(),
|
|
629
|
+
});
|
|
588
630
|
}
|
|
589
631
|
|
|
590
632
|
const MAX_RATE_HZ_IN_MILLISECOND = 1000.0;
|
|
591
633
|
if (hz <= 0.0 || hz > MAX_RATE_HZ_IN_MILLISECOND) {
|
|
592
|
-
throw new
|
|
593
|
-
|
|
634
|
+
throw new RangeValidationError(
|
|
635
|
+
'hz',
|
|
636
|
+
hz,
|
|
637
|
+
`0.0 < hz <= ${MAX_RATE_HZ_IN_MILLISECOND}`,
|
|
638
|
+
{
|
|
639
|
+
nodeName: this.name(),
|
|
640
|
+
}
|
|
594
641
|
);
|
|
595
642
|
}
|
|
596
643
|
|
|
@@ -635,12 +682,32 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
635
682
|
}
|
|
636
683
|
options = this._validateOptions(options);
|
|
637
684
|
|
|
685
|
+
if (typeof typeClass !== 'function') {
|
|
686
|
+
throw new TypeValidationError('typeClass', typeClass, 'function', {
|
|
687
|
+
nodeName: this.name(),
|
|
688
|
+
entityType: 'publisher',
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
if (typeof topic !== 'string') {
|
|
692
|
+
throw new TypeValidationError('topic', topic, 'string', {
|
|
693
|
+
nodeName: this.name(),
|
|
694
|
+
entityType: 'publisher',
|
|
695
|
+
});
|
|
696
|
+
}
|
|
638
697
|
if (
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
(eventCallbacks && !(eventCallbacks instanceof PublisherEventCallbacks))
|
|
698
|
+
eventCallbacks &&
|
|
699
|
+
!(eventCallbacks instanceof PublisherEventCallbacks)
|
|
642
700
|
) {
|
|
643
|
-
throw new
|
|
701
|
+
throw new TypeValidationError(
|
|
702
|
+
'eventCallbacks',
|
|
703
|
+
eventCallbacks,
|
|
704
|
+
'PublisherEventCallbacks',
|
|
705
|
+
{
|
|
706
|
+
nodeName: this.name(),
|
|
707
|
+
entityType: 'publisher',
|
|
708
|
+
entityName: topic,
|
|
709
|
+
}
|
|
710
|
+
);
|
|
644
711
|
}
|
|
645
712
|
|
|
646
713
|
let publisher = publisherClass.createPublisher(
|
|
@@ -704,14 +771,39 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
704
771
|
}
|
|
705
772
|
options = this._validateOptions(options);
|
|
706
773
|
|
|
774
|
+
if (typeof typeClass !== 'function') {
|
|
775
|
+
throw new TypeValidationError('typeClass', typeClass, 'function', {
|
|
776
|
+
nodeName: this.name(),
|
|
777
|
+
entityType: 'subscription',
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
if (typeof topic !== 'string') {
|
|
781
|
+
throw new TypeValidationError('topic', topic, 'string', {
|
|
782
|
+
nodeName: this.name(),
|
|
783
|
+
entityType: 'subscription',
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
if (typeof callback !== 'function') {
|
|
787
|
+
throw new TypeValidationError('callback', callback, 'function', {
|
|
788
|
+
nodeName: this.name(),
|
|
789
|
+
entityType: 'subscription',
|
|
790
|
+
entityName: topic,
|
|
791
|
+
});
|
|
792
|
+
}
|
|
707
793
|
if (
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
typeof callback !== 'function' ||
|
|
711
|
-
(eventCallbacks &&
|
|
712
|
-
!(eventCallbacks instanceof SubscriptionEventCallbacks))
|
|
794
|
+
eventCallbacks &&
|
|
795
|
+
!(eventCallbacks instanceof SubscriptionEventCallbacks)
|
|
713
796
|
) {
|
|
714
|
-
throw new
|
|
797
|
+
throw new TypeValidationError(
|
|
798
|
+
'eventCallbacks',
|
|
799
|
+
eventCallbacks,
|
|
800
|
+
'SubscriptionEventCallbacks',
|
|
801
|
+
{
|
|
802
|
+
nodeName: this.name(),
|
|
803
|
+
entityType: 'subscription',
|
|
804
|
+
entityName: topic,
|
|
805
|
+
}
|
|
806
|
+
);
|
|
715
807
|
}
|
|
716
808
|
|
|
717
809
|
let subscription = Subscription.createSubscription(
|
|
@@ -729,6 +821,42 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
729
821
|
return subscription;
|
|
730
822
|
}
|
|
731
823
|
|
|
824
|
+
/**
|
|
825
|
+
* Create a Subscription that returns an RxJS Observable.
|
|
826
|
+
* This allows using reactive programming patterns with ROS 2 messages.
|
|
827
|
+
*
|
|
828
|
+
* @param {function|string|object} typeClass - The ROS message class,
|
|
829
|
+
* OR a string representing the message class, e.g. 'std_msgs/msg/String',
|
|
830
|
+
* OR an object representing the message class, e.g. {package: 'std_msgs', type: 'msg', name: 'String'}
|
|
831
|
+
* @param {string} topic - The name of the topic.
|
|
832
|
+
* @param {object} [options] - The options argument used to parameterize the subscription.
|
|
833
|
+
* @param {boolean} [options.enableTypedArray=true] - The topic will use TypedArray if necessary.
|
|
834
|
+
* @param {QoS} [options.qos=QoS.profileDefault] - ROS Middleware "quality of service" settings.
|
|
835
|
+
* @param {boolean} [options.isRaw=false] - The topic is serialized when true.
|
|
836
|
+
* @param {string} [options.serializationMode='default'] - Controls message serialization format.
|
|
837
|
+
* @param {object} [options.contentFilter] - The content-filter (if supported by RMW).
|
|
838
|
+
* @param {SubscriptionEventCallbacks} [eventCallbacks] - The event callbacks for the subscription.
|
|
839
|
+
* @return {ObservableSubscription} - An ObservableSubscription with an RxJS Observable.
|
|
840
|
+
*/
|
|
841
|
+
createObservableSubscription(typeClass, topic, options, eventCallbacks) {
|
|
842
|
+
let observableSubscription = null;
|
|
843
|
+
|
|
844
|
+
const subscription = this.createSubscription(
|
|
845
|
+
typeClass,
|
|
846
|
+
topic,
|
|
847
|
+
options,
|
|
848
|
+
(message) => {
|
|
849
|
+
if (observableSubscription) {
|
|
850
|
+
observableSubscription._emit(message);
|
|
851
|
+
}
|
|
852
|
+
},
|
|
853
|
+
eventCallbacks
|
|
854
|
+
);
|
|
855
|
+
|
|
856
|
+
observableSubscription = new ObservableSubscription(subscription);
|
|
857
|
+
return observableSubscription;
|
|
858
|
+
}
|
|
859
|
+
|
|
732
860
|
/**
|
|
733
861
|
* Create a Client.
|
|
734
862
|
* @param {function|string|object} typeClass - The ROS message class,
|
|
@@ -746,8 +874,17 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
746
874
|
}
|
|
747
875
|
options = this._validateOptions(options);
|
|
748
876
|
|
|
749
|
-
if (typeof typeClass !== 'function'
|
|
750
|
-
throw new
|
|
877
|
+
if (typeof typeClass !== 'function') {
|
|
878
|
+
throw new TypeValidationError('typeClass', typeClass, 'function', {
|
|
879
|
+
nodeName: this.name(),
|
|
880
|
+
entityType: 'client',
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
if (typeof serviceName !== 'string') {
|
|
884
|
+
throw new TypeValidationError('serviceName', serviceName, 'string', {
|
|
885
|
+
nodeName: this.name(),
|
|
886
|
+
entityType: 'client',
|
|
887
|
+
});
|
|
751
888
|
}
|
|
752
889
|
|
|
753
890
|
let client = Client.createClient(
|
|
@@ -801,12 +938,24 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
801
938
|
}
|
|
802
939
|
options = this._validateOptions(options);
|
|
803
940
|
|
|
804
|
-
if (
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
941
|
+
if (typeof typeClass !== 'function') {
|
|
942
|
+
throw new TypeValidationError('typeClass', typeClass, 'function', {
|
|
943
|
+
nodeName: this.name(),
|
|
944
|
+
entityType: 'service',
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
if (typeof serviceName !== 'string') {
|
|
948
|
+
throw new TypeValidationError('serviceName', serviceName, 'string', {
|
|
949
|
+
nodeName: this.name(),
|
|
950
|
+
entityType: 'service',
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
if (typeof callback !== 'function') {
|
|
954
|
+
throw new TypeValidationError('callback', callback, 'function', {
|
|
955
|
+
nodeName: this.name(),
|
|
956
|
+
entityType: 'service',
|
|
957
|
+
entityName: serviceName,
|
|
958
|
+
});
|
|
810
959
|
}
|
|
811
960
|
|
|
812
961
|
let service = Service.createService(
|
|
@@ -823,6 +972,52 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
823
972
|
return service;
|
|
824
973
|
}
|
|
825
974
|
|
|
975
|
+
/**
|
|
976
|
+
* Create a ParameterClient for accessing parameters on a remote node.
|
|
977
|
+
* @param {string} remoteNodeName - The name of the remote node whose parameters to access.
|
|
978
|
+
* @param {object} [options] - Options for parameter client.
|
|
979
|
+
* @param {number} [options.timeout=5000] - Default timeout in milliseconds for service calls.
|
|
980
|
+
* @return {ParameterClient} - An instance of ParameterClient.
|
|
981
|
+
*/
|
|
982
|
+
createParameterClient(remoteNodeName, options = {}) {
|
|
983
|
+
if (typeof remoteNodeName !== 'string' || remoteNodeName.trim() === '') {
|
|
984
|
+
throw new TypeError('Remote node name must be a non-empty string');
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
const parameterClient = new ParameterClient(this, remoteNodeName, options);
|
|
988
|
+
debug(
|
|
989
|
+
'Finish creating parameter client for remote node = %s.',
|
|
990
|
+
remoteNodeName
|
|
991
|
+
);
|
|
992
|
+
this._parameterClients.push(parameterClient);
|
|
993
|
+
|
|
994
|
+
return parameterClient;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
/**
|
|
998
|
+
* Create a ParameterWatcher for watching parameter changes on a remote node.
|
|
999
|
+
* @param {string} remoteNodeName - The name of the remote node whose parameters to watch.
|
|
1000
|
+
* @param {string[]} parameterNames - Array of parameter names to watch.
|
|
1001
|
+
* @param {object} [options] - Options for parameter watcher.
|
|
1002
|
+
* @param {number} [options.timeout=5000] - Default timeout in milliseconds for service calls.
|
|
1003
|
+
* @return {ParameterWatcher} - An instance of ParameterWatcher.
|
|
1004
|
+
*/
|
|
1005
|
+
createParameterWatcher(remoteNodeName, parameterNames, options = {}) {
|
|
1006
|
+
const watcher = new ParameterWatcher(
|
|
1007
|
+
this,
|
|
1008
|
+
remoteNodeName,
|
|
1009
|
+
parameterNames,
|
|
1010
|
+
options
|
|
1011
|
+
);
|
|
1012
|
+
debug(
|
|
1013
|
+
'Finish creating parameter watcher for remote node = %s.',
|
|
1014
|
+
remoteNodeName
|
|
1015
|
+
);
|
|
1016
|
+
this._parameterWatchers.push(watcher);
|
|
1017
|
+
|
|
1018
|
+
return watcher;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
826
1021
|
/**
|
|
827
1022
|
* Create a guard condition.
|
|
828
1023
|
* @param {Function} callback - The callback to be called when the guard condition is triggered.
|
|
@@ -830,7 +1025,10 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
830
1025
|
*/
|
|
831
1026
|
createGuardCondition(callback) {
|
|
832
1027
|
if (typeof callback !== 'function') {
|
|
833
|
-
throw new
|
|
1028
|
+
throw new TypeValidationError('callback', callback, 'function', {
|
|
1029
|
+
nodeName: this.name(),
|
|
1030
|
+
entityType: 'guard_condition',
|
|
1031
|
+
});
|
|
834
1032
|
}
|
|
835
1033
|
|
|
836
1034
|
let guard = GuardCondition.createGuardCondition(callback, this.context);
|
|
@@ -856,8 +1054,16 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
856
1054
|
this._actionClients.forEach((actionClient) => actionClient.destroy());
|
|
857
1055
|
this._actionServers.forEach((actionServer) => actionServer.destroy());
|
|
858
1056
|
|
|
1057
|
+
this._parameterClients.forEach((paramClient) => paramClient.destroy());
|
|
1058
|
+
this._parameterWatchers.forEach((watcher) => watcher.destroy());
|
|
1059
|
+
|
|
859
1060
|
this.context.onNodeDestroyed(this);
|
|
860
1061
|
|
|
1062
|
+
if (this._enableRosout) {
|
|
1063
|
+
rclnodejs.finiRosoutPublisherForNode(this.handle);
|
|
1064
|
+
this._enableRosout = false;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
861
1067
|
this.handle.release();
|
|
862
1068
|
this._clock = null;
|
|
863
1069
|
this._timers = [];
|
|
@@ -868,6 +1074,8 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
868
1074
|
this._guards = [];
|
|
869
1075
|
this._actionClients = [];
|
|
870
1076
|
this._actionServers = [];
|
|
1077
|
+
this._parameterClients = [];
|
|
1078
|
+
this._parameterWatchers = [];
|
|
871
1079
|
|
|
872
1080
|
if (this._rateTimerServer) {
|
|
873
1081
|
this._rateTimerServer.shutdown();
|
|
@@ -882,7 +1090,14 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
882
1090
|
*/
|
|
883
1091
|
destroyPublisher(publisher) {
|
|
884
1092
|
if (!(publisher instanceof Publisher)) {
|
|
885
|
-
throw new
|
|
1093
|
+
throw new TypeValidationError(
|
|
1094
|
+
'publisher',
|
|
1095
|
+
publisher,
|
|
1096
|
+
'Publisher instance',
|
|
1097
|
+
{
|
|
1098
|
+
nodeName: this.name(),
|
|
1099
|
+
}
|
|
1100
|
+
);
|
|
886
1101
|
}
|
|
887
1102
|
if (publisher.events) {
|
|
888
1103
|
publisher.events.forEach((event) => {
|
|
@@ -900,7 +1115,14 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
900
1115
|
*/
|
|
901
1116
|
destroySubscription(subscription) {
|
|
902
1117
|
if (!(subscription instanceof Subscription)) {
|
|
903
|
-
throw new
|
|
1118
|
+
throw new TypeValidationError(
|
|
1119
|
+
'subscription',
|
|
1120
|
+
subscription,
|
|
1121
|
+
'Subscription instance',
|
|
1122
|
+
{
|
|
1123
|
+
nodeName: this.name(),
|
|
1124
|
+
}
|
|
1125
|
+
);
|
|
904
1126
|
}
|
|
905
1127
|
if (subscription.events) {
|
|
906
1128
|
subscription.events.forEach((event) => {
|
|
@@ -919,7 +1141,9 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
919
1141
|
*/
|
|
920
1142
|
destroyClient(client) {
|
|
921
1143
|
if (!(client instanceof Client)) {
|
|
922
|
-
throw new
|
|
1144
|
+
throw new TypeValidationError('client', client, 'Client instance', {
|
|
1145
|
+
nodeName: this.name(),
|
|
1146
|
+
});
|
|
923
1147
|
}
|
|
924
1148
|
this._destroyEntity(client, this._clients);
|
|
925
1149
|
}
|
|
@@ -931,11 +1155,39 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
931
1155
|
*/
|
|
932
1156
|
destroyService(service) {
|
|
933
1157
|
if (!(service instanceof Service)) {
|
|
934
|
-
throw new
|
|
1158
|
+
throw new TypeValidationError('service', service, 'Service instance', {
|
|
1159
|
+
nodeName: this.name(),
|
|
1160
|
+
});
|
|
935
1161
|
}
|
|
936
1162
|
this._destroyEntity(service, this._services);
|
|
937
1163
|
}
|
|
938
1164
|
|
|
1165
|
+
/**
|
|
1166
|
+
* Destroy a ParameterClient.
|
|
1167
|
+
* @param {ParameterClient} parameterClient - The ParameterClient to be destroyed.
|
|
1168
|
+
* @return {undefined}
|
|
1169
|
+
*/
|
|
1170
|
+
destroyParameterClient(parameterClient) {
|
|
1171
|
+
if (!(parameterClient instanceof ParameterClient)) {
|
|
1172
|
+
throw new TypeError('Invalid argument');
|
|
1173
|
+
}
|
|
1174
|
+
this._removeEntityFromArray(parameterClient, this._parameterClients);
|
|
1175
|
+
parameterClient.destroy();
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
/**
|
|
1179
|
+
* Destroy a ParameterWatcher.
|
|
1180
|
+
* @param {ParameterWatcher} watcher - The ParameterWatcher to be destroyed.
|
|
1181
|
+
* @return {undefined}
|
|
1182
|
+
*/
|
|
1183
|
+
destroyParameterWatcher(watcher) {
|
|
1184
|
+
if (!(watcher instanceof ParameterWatcher)) {
|
|
1185
|
+
throw new TypeError('Invalid argument');
|
|
1186
|
+
}
|
|
1187
|
+
this._removeEntityFromArray(watcher, this._parameterWatchers);
|
|
1188
|
+
watcher.destroy();
|
|
1189
|
+
}
|
|
1190
|
+
|
|
939
1191
|
/**
|
|
940
1192
|
* Destroy a Timer.
|
|
941
1193
|
* @param {Timer} timer - The Timer to be destroyed.
|
|
@@ -943,7 +1195,9 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
943
1195
|
*/
|
|
944
1196
|
destroyTimer(timer) {
|
|
945
1197
|
if (!(timer instanceof Timer)) {
|
|
946
|
-
throw new
|
|
1198
|
+
throw new TypeValidationError('timer', timer, 'Timer instance', {
|
|
1199
|
+
nodeName: this.name(),
|
|
1200
|
+
});
|
|
947
1201
|
}
|
|
948
1202
|
this._destroyEntity(timer, this._timers);
|
|
949
1203
|
}
|
|
@@ -955,7 +1209,9 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
955
1209
|
*/
|
|
956
1210
|
destroyGuardCondition(guard) {
|
|
957
1211
|
if (!(guard instanceof GuardCondition)) {
|
|
958
|
-
throw new
|
|
1212
|
+
throw new TypeValidationError('guard', guard, 'GuardCondition instance', {
|
|
1213
|
+
nodeName: this.name(),
|
|
1214
|
+
});
|
|
959
1215
|
}
|
|
960
1216
|
this._destroyEntity(guard, this._guards);
|
|
961
1217
|
}
|
|
@@ -1002,7 +1258,7 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
1002
1258
|
|
|
1003
1259
|
/**
|
|
1004
1260
|
* Get the current time using the node's clock.
|
|
1005
|
-
* @returns {
|
|
1261
|
+
* @returns {Timer} - The current time.
|
|
1006
1262
|
*/
|
|
1007
1263
|
now() {
|
|
1008
1264
|
return this.getClock().now();
|
|
@@ -1141,6 +1397,74 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
1141
1397
|
);
|
|
1142
1398
|
}
|
|
1143
1399
|
|
|
1400
|
+
/**
|
|
1401
|
+
* Return a list of clients on a given service.
|
|
1402
|
+
*
|
|
1403
|
+
* The returned parameter is a list of ServiceEndpointInfo objects, where each will contain
|
|
1404
|
+
* the node name, node namespace, service type, service endpoint's GID, and its QoS profile.
|
|
1405
|
+
*
|
|
1406
|
+
* When the `no_mangle` parameter is `true`, the provided `service` should be a valid
|
|
1407
|
+
* service name for the middleware (useful when combining ROS with native middleware (e.g. DDS)
|
|
1408
|
+
* apps). When the `no_mangle` parameter is `false`, the provided `service` should
|
|
1409
|
+
* follow ROS service name conventions.
|
|
1410
|
+
*
|
|
1411
|
+
* `service` may be a relative, private, or fully qualified service name.
|
|
1412
|
+
* A relative or private service will be expanded using this node's namespace and name.
|
|
1413
|
+
* The queried `service` is not remapped.
|
|
1414
|
+
*
|
|
1415
|
+
* @param {string} service - The service on which to find the clients.
|
|
1416
|
+
* @param {boolean} [noDemangle=false] - If `true`, `service` needs to be a valid middleware service
|
|
1417
|
+
* name, otherwise it should be a valid ROS service name. Defaults to `false`.
|
|
1418
|
+
* @returns {Array} - list of clients
|
|
1419
|
+
*/
|
|
1420
|
+
getClientsInfoByService(service, noDemangle = false) {
|
|
1421
|
+
if (DistroUtils.getDistroId() < DistroUtils.DistroId.ROLLING) {
|
|
1422
|
+
console.warn(
|
|
1423
|
+
'getClientsInfoByService is not supported by this version of ROS 2'
|
|
1424
|
+
);
|
|
1425
|
+
return null;
|
|
1426
|
+
}
|
|
1427
|
+
return rclnodejs.getClientsInfoByService(
|
|
1428
|
+
this.handle,
|
|
1429
|
+
this._getValidatedServiceName(service, noDemangle),
|
|
1430
|
+
noDemangle
|
|
1431
|
+
);
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
/**
|
|
1435
|
+
* Return a list of servers on a given service.
|
|
1436
|
+
*
|
|
1437
|
+
* The returned parameter is a list of ServiceEndpointInfo objects, where each will contain
|
|
1438
|
+
* the node name, node namespace, service type, service endpoint's GID, and its QoS profile.
|
|
1439
|
+
*
|
|
1440
|
+
* When the `no_mangle` parameter is `true`, the provided `service` should be a valid
|
|
1441
|
+
* service name for the middleware (useful when combining ROS with native middleware (e.g. DDS)
|
|
1442
|
+
* apps). When the `no_mangle` parameter is `false`, the provided `service` should
|
|
1443
|
+
* follow ROS service name conventions.
|
|
1444
|
+
*
|
|
1445
|
+
* `service` may be a relative, private, or fully qualified service name.
|
|
1446
|
+
* A relative or private service will be expanded using this node's namespace and name.
|
|
1447
|
+
* The queried `service` is not remapped.
|
|
1448
|
+
*
|
|
1449
|
+
* @param {string} service - The service on which to find the servers.
|
|
1450
|
+
* @param {boolean} [noDemangle=false] - If `true`, `service` needs to be a valid middleware service
|
|
1451
|
+
* name, otherwise it should be a valid ROS service name. Defaults to `false`.
|
|
1452
|
+
* @returns {Array} - list of servers
|
|
1453
|
+
*/
|
|
1454
|
+
getServersInfoByService(service, noDemangle = false) {
|
|
1455
|
+
if (DistroUtils.getDistroId() < DistroUtils.DistroId.ROLLING) {
|
|
1456
|
+
console.warn(
|
|
1457
|
+
'getServersInfoByService is not supported by this version of ROS 2'
|
|
1458
|
+
);
|
|
1459
|
+
return null;
|
|
1460
|
+
}
|
|
1461
|
+
return rclnodejs.getServersInfoByService(
|
|
1462
|
+
this.handle,
|
|
1463
|
+
this._getValidatedServiceName(service, noDemangle),
|
|
1464
|
+
noDemangle
|
|
1465
|
+
);
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1144
1468
|
/**
|
|
1145
1469
|
* Get the list of nodes discovered by the provided node.
|
|
1146
1470
|
* @return {Array<string>} - An array of the names.
|
|
@@ -1247,14 +1571,14 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
1247
1571
|
*
|
|
1248
1572
|
* @param {Parameter} parameter - Parameter to declare.
|
|
1249
1573
|
* @param {ParameterDescriptor} [descriptor] - Optional descriptor for parameter.
|
|
1250
|
-
* @param {boolean} [
|
|
1574
|
+
* @param {boolean} [ignoreOverride] - When true disregard any parameter-override that may be present.
|
|
1251
1575
|
* @return {Parameter} - The newly declared parameter.
|
|
1252
1576
|
*/
|
|
1253
|
-
declareParameter(parameter, descriptor,
|
|
1577
|
+
declareParameter(parameter, descriptor, ignoreOverride = false) {
|
|
1254
1578
|
const parameters = this.declareParameters(
|
|
1255
1579
|
[parameter],
|
|
1256
1580
|
descriptor ? [descriptor] : [],
|
|
1257
|
-
|
|
1581
|
+
ignoreOverride
|
|
1258
1582
|
);
|
|
1259
1583
|
return parameters.length == 1 ? parameters[0] : null;
|
|
1260
1584
|
}
|
|
@@ -1295,16 +1619,25 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
1295
1619
|
*/
|
|
1296
1620
|
declareParameters(parameters, descriptors = [], ignoreOverrides = false) {
|
|
1297
1621
|
if (!Array.isArray(parameters)) {
|
|
1298
|
-
throw new
|
|
1622
|
+
throw new TypeValidationError('parameters', parameters, 'Array', {
|
|
1623
|
+
nodeName: this.name(),
|
|
1624
|
+
});
|
|
1299
1625
|
}
|
|
1300
1626
|
if (!Array.isArray(descriptors)) {
|
|
1301
|
-
throw new
|
|
1302
|
-
|
|
1303
|
-
);
|
|
1627
|
+
throw new TypeValidationError('descriptors', descriptors, 'Array', {
|
|
1628
|
+
nodeName: this.name(),
|
|
1629
|
+
});
|
|
1304
1630
|
}
|
|
1305
1631
|
if (descriptors.length > 0 && parameters.length !== descriptors.length) {
|
|
1306
|
-
throw new
|
|
1307
|
-
'Each parameter must have a
|
|
1632
|
+
throw new ValidationError(
|
|
1633
|
+
'Each parameter must have a corresponding ParameterDescriptor',
|
|
1634
|
+
{
|
|
1635
|
+
code: 'PARAMETER_DESCRIPTOR_MISMATCH',
|
|
1636
|
+
argumentName: 'descriptors',
|
|
1637
|
+
providedValue: descriptors.length,
|
|
1638
|
+
expectedType: `Array with length ${parameters.length}`,
|
|
1639
|
+
nodeName: this.name(),
|
|
1640
|
+
}
|
|
1308
1641
|
);
|
|
1309
1642
|
}
|
|
1310
1643
|
|
|
@@ -1744,7 +2077,9 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
1744
2077
|
*/
|
|
1745
2078
|
resolveTopicName(topicName, onlyExpand = false) {
|
|
1746
2079
|
if (typeof topicName !== 'string') {
|
|
1747
|
-
throw new
|
|
2080
|
+
throw new TypeValidationError('topicName', topicName, 'string', {
|
|
2081
|
+
nodeName: this.name(),
|
|
2082
|
+
});
|
|
1748
2083
|
}
|
|
1749
2084
|
return rclnodejs.resolveName(
|
|
1750
2085
|
this.handle,
|
|
@@ -1762,7 +2097,9 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
1762
2097
|
*/
|
|
1763
2098
|
resolveServiceName(service, onlyExpand = false) {
|
|
1764
2099
|
if (typeof service !== 'string') {
|
|
1765
|
-
throw new
|
|
2100
|
+
throw new TypeValidationError('service', service, 'string', {
|
|
2101
|
+
nodeName: this.name(),
|
|
2102
|
+
});
|
|
1766
2103
|
}
|
|
1767
2104
|
return rclnodejs.resolveName(
|
|
1768
2105
|
this.handle,
|
|
@@ -1921,6 +2258,22 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
1921
2258
|
validateFullTopicName(fqTopicName);
|
|
1922
2259
|
return rclnodejs.remapTopicName(this.handle, fqTopicName);
|
|
1923
2260
|
}
|
|
2261
|
+
|
|
2262
|
+
_getValidatedServiceName(serviceName, noDemangle) {
|
|
2263
|
+
if (typeof serviceName !== 'string') {
|
|
2264
|
+
throw new TypeValidationError('serviceName', serviceName, 'string', {
|
|
2265
|
+
nodeName: this.name(),
|
|
2266
|
+
});
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
if (noDemangle) {
|
|
2270
|
+
return serviceName;
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2273
|
+
const resolvedServiceName = this.resolveServiceName(serviceName);
|
|
2274
|
+
rclnodejs.validateTopicName(resolvedServiceName);
|
|
2275
|
+
return resolvedServiceName;
|
|
2276
|
+
}
|
|
1924
2277
|
}
|
|
1925
2278
|
|
|
1926
2279
|
/**
|