rclrb 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.
data/lib/rclrb/capi.rb ADDED
@@ -0,0 +1,369 @@
1
+ require 'ffi'
2
+
3
+ module Rclrb
4
+ ##
5
+ # This module contains the function and data structures used to interface with the RCL C library
6
+ # The content of CApi is internal API to rclrb and should not be directly called and is subject
7
+ # to change.
8
+ module CApi
9
+ extend FFI::Library
10
+ ffi_lib 'rcl'
11
+
12
+ RCL_RET_OK = 0
13
+ RCL_RET_TIMEOUT = 2
14
+ RCL_RET_SUBSCRIPTION_TAKE_FAILED = 401
15
+ RCL_RET_CLIENT_TAKE_FAILED = 501
16
+ RCL_RET_SERVICE_TAKE_FAILED = 601
17
+
18
+ RCUTILS_ERROR_MESSAGE_MAX_LENGTH = 1024
19
+ RMW_GID_STORAGE_SIZE = 24
20
+
21
+ POINTER_SIZE = FFI::Pointer::SIZE
22
+ SIZE_T_SIZE = FFI::type_size(:size_t)
23
+ INT32_SIZE = FFI::type_size(:int32)
24
+ UINT32_SIZE = FFI::type_size(:uint32)
25
+
26
+ # Rcutils structs
27
+ class RcutilsErrorStringT < FFI::Struct
28
+ layout :str, [:uint8, RCUTILS_ERROR_MESSAGE_MAX_LENGTH]
29
+ end
30
+
31
+ # Rmw structs
32
+ enum :RmwQosReliabilityPolicyE, [
33
+ :RMW_QOS_POLICY_RELIABILITY_SYSTEM_DEFAULT,
34
+ :RMW_QOS_POLICY_RELIABILITY_RELIABLE,
35
+ :RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT,
36
+ :RMW_QOS_POLICY_RELIABILITY_UNKNOWN
37
+ ]
38
+ enum :RmwQosDdurabilityPolicy, [
39
+ :RMW_QOS_POLICY_DURABILITY_SYSTEM_DEFAULT,
40
+ :RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL,
41
+ :RMW_QOS_POLICY_DURABILITY_VOLATILE,
42
+ :RMW_QOS_POLICY_DURABILITY_UNKNOWN
43
+ ]
44
+ enum :RmwQosLivelinessPolicy, [
45
+ :RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT,
46
+ :RMW_QOS_POLICY_LIVELINESS_AUTOMATIC,
47
+ :RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_NODE_DEPRECATED,
48
+ :RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC,
49
+ :RMW_QOS_POLICY_LIVELINESS_UNKNOWN
50
+ ]
51
+ enum :RmwQosGistoryPolicyE, [
52
+ :RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT,
53
+ :RMW_QOS_POLICY_HISTORY_KEEP_LAST,
54
+ :RMW_QOS_POLICY_HISTORY_KEEP_ALL,
55
+ :RMW_QOS_POLICY_HISTORY_UNKNOWN
56
+ ]
57
+
58
+ enum :rmw_unique_network_flow_endpoints_requirement_e, []
59
+
60
+ class RmwTimeS < FFI::Struct
61
+ layout :sec, :uint64, :nsec, :uint64
62
+ end
63
+
64
+ class RmwQoSProfileT < FFI::Struct
65
+ layout :history, :RmwQosGistoryPolicyE,
66
+ :depth, :size_t,
67
+ :reliability, :RmwQosReliabilityPolicyE,
68
+ :durability, :RmwQosDdurabilityPolicy,
69
+ :deadline, RmwTimeS,
70
+ :lifespan, RmwTimeS,
71
+ :liveliness, :RmwQosLivelinessPolicy,
72
+ :liveliness_lease_duration, RmwTimeS,
73
+ :avoid_ros_namespace_conventions, :bool
74
+ end
75
+
76
+ class RmwSubscriptionOptionsT < FFI::Struct
77
+ layout :rmw_specific_subscription_payload, :pointer,
78
+ :ignore_local_publications, :bool,
79
+ :require_unique_network_flow_endpoints, :rmw_unique_network_flow_endpoints_requirement_e,
80
+ :content_filter_options, :pointer
81
+ end
82
+
83
+ class RmwPublisherOptionsT < FFI::Struct
84
+ layout :rmw_specific_publisher_payload, :pointer,
85
+ :require_unique_network_flow_endpoints, :rmw_unique_network_flow_endpoints_requirement_e
86
+ end
87
+
88
+ class RmwGidT < FFI::Struct
89
+ layout :implementation_identifier, :string,
90
+ :data, [:uint8, RMW_GID_STORAGE_SIZE]
91
+ end
92
+
93
+ RmwTimePointValueT = :int64
94
+
95
+ class RmwMessageInfoT < FFI::Struct
96
+ layout :source_timestamp, RmwTimePointValueT,
97
+ :received_timestamp, RmwTimePointValueT,
98
+ :publication_sequence_number, :uint64,
99
+ :reception_sequence_number, :uint64,
100
+ :publisher_gid, RmwGidT,
101
+ :from_intra_process, :bool
102
+ end
103
+
104
+ class RmwSubscriptionAllocationT < FFI::Struct
105
+ layout :implementation_identifier, :string,
106
+ :data, :pointer
107
+ end
108
+
109
+ class RmwPublisherAllocationT < FFI::Struct
110
+ layout :implementation_identifier, :string,
111
+ :data, :pointer
112
+ end
113
+
114
+ class RmwRequestIdT < FFI::Struct
115
+ layout :writer_guid, [:int16, 16],
116
+ :sequence_number, :int64
117
+ end
118
+
119
+ class RmwServiceInfoT < FFI::Struct
120
+ layout :source_timestamp, RmwTimePointValueT,
121
+ :received_timestamp, RmwTimePointValueT,
122
+ :request_id, RmwRequestIdT
123
+ end
124
+
125
+ # Rosidl
126
+
127
+ class RosidlMessageTypeSupportT < FFI::Struct
128
+ layout :typesuport_identifier, :string,
129
+ :data, :pointer,
130
+ :func, :pointer
131
+ end
132
+
133
+ class RosidlServiceTypeSupportT < FFI::Struct
134
+ layout :typesuport_identifier, :string,
135
+ :data, :pointer,
136
+ :func, :pointer
137
+ end
138
+
139
+ # Rcl
140
+ callback :allocate_callback, [:size_t, :pointer], :pointer
141
+ callback :deallocate_callback, [:pointer, :pointer], :void
142
+
143
+ class RclAllocatorT < FFI::Struct
144
+ layout :allocate, :allocate_callback, :deallocate, :deallocate_callback,
145
+ :reallocate, :pointer, :zero_allocate, :pointer,
146
+ :state, :pointer
147
+ end
148
+
149
+ class RclArgumentsT < FFI::Struct
150
+ layout :impl, :pointer
151
+ end
152
+
153
+ class RclContextT < FFI::Struct
154
+ layout :global_arguments, RclArgumentsT,
155
+ :impl, :pointer,
156
+ :instance_id_storage, [:uint8, 8]
157
+ end
158
+
159
+ class RclInitOptionsT < FFI::Struct
160
+ layout :impl, :pointer
161
+ end
162
+
163
+ enum :RclClockTypeT, [:RCL_CLOCK_UNINITIALIZED, :RCL_ROS_TIME, :RCL_SYSTEM_TIME, :RCL_STEADY_TIME]
164
+
165
+ class RclClockT < FFI::Struct
166
+ layout :type, :RclClockTypeT,
167
+ :jump_callbacks, :pointer,
168
+ :num_jump_callbacks, :size_t,
169
+ :now, :pointer,
170
+ :data, :pointer,
171
+ :allocator, RclAllocatorT
172
+ end
173
+
174
+ class RclNodeT < FFI::Struct
175
+ layout :context, :pointer, :impl, :pointer
176
+ end
177
+
178
+ class RclSubscriptionOptionsT < FFI::Struct
179
+ layout :qos, RmwQoSProfileT, :allocator, RclAllocatorT, :rmw_subscription_options, RmwSubscriptionOptionsT
180
+ end
181
+
182
+ class RclPublisherOptionsT < FFI::Struct
183
+ layout :qos, RmwQoSProfileT, :allocator, RclAllocatorT, :rmw_subscription_options, RmwPublisherOptionsT
184
+ end
185
+
186
+ class RclServiceOptionsT < FFI::Struct
187
+ layout :qos, RmwQoSProfileT, :allocator, RclAllocatorT
188
+ end
189
+
190
+ class RclClientOptionsT < FFI::Struct
191
+ layout :qos, RmwQoSProfileT, :allocator, RclAllocatorT
192
+ end
193
+
194
+ class RclGuardConditionOptionsT < FFI::Struct
195
+ layout :allocator, RclAllocatorT
196
+ end
197
+
198
+ class RclSubscriptionT < FFI::Struct
199
+ layout :impl, :pointer
200
+ end
201
+
202
+ class RclPublisherT < FFI::Struct
203
+ layout :impl, :pointer
204
+ end
205
+
206
+ class RclServiceT < FFI::Struct
207
+ layout :impl, :pointer
208
+ end
209
+
210
+ class RclClientT < FFI::Struct
211
+ layout :impl, :pointer
212
+ end
213
+
214
+ class RclGuardConditionT < FFI::Struct
215
+ layout :context, RclContextT.by_ref,
216
+ :impl, :pointer
217
+ end
218
+
219
+ class RclTimerT < FFI::Struct
220
+ layout :impl, :pointer
221
+ end
222
+
223
+ class RclNodeOptionsT < FFI::Struct
224
+ layout :allocator, RclAllocatorT, :use_global_arguments, :bool,
225
+ :arguments, RclArgumentsT, :enable_rosout, :bool,
226
+ :rosout_qos, RmwQoSProfileT
227
+ end
228
+
229
+ class RclWaitSetT < FFI::Struct
230
+ layout :subscriptions, :pointer,
231
+ :size_of_subscriptions, :size_t,
232
+ :guard_conditions, :pointer,
233
+ :size_of_guard_conditions, :size_t,
234
+ :timers, :pointer,
235
+ :size_of_timers, :size_t,
236
+ :clients, :pointer,
237
+ :size_of_clients, :size_t,
238
+ :services, :pointer,
239
+ :size_of_services, :size_t,
240
+ :events, :pointer,
241
+ :size_of_events, :size_t,
242
+ :impl, :pointer
243
+ end
244
+
245
+ # Misc
246
+
247
+ RclRetT = :int
248
+ class BoolPtr < FFI::Struct
249
+ layout :value, :bool
250
+ end
251
+ class Int64Ptr < FFI::Struct
252
+ layout :value, :int64
253
+ end
254
+ class SizeTPtr < FFI::Struct
255
+ layout :value, :size_t
256
+ end
257
+
258
+ # init API
259
+ attach_function :rcl_get_zero_initialized_context, [], RclContextT.by_value
260
+ attach_function :rcl_context_fini, [:pointer], :int
261
+ attach_function :rcl_get_zero_initialized_init_options, [], RclInitOptionsT.by_value
262
+ attach_function :rcl_init_options_init, [RclInitOptionsT.by_ref, RclAllocatorT.by_value], RclRetT
263
+ attach_function :rcl_init, [:int, :pointer, RclInitOptionsT.by_ref, RclContextT.by_ref], RclRetT
264
+
265
+ # Node API
266
+ attach_function :rcl_node_init, [RclNodeT.by_ref, :string, :string, RclContextT.by_ref, RclNodeOptionsT.by_ref], RclRetT
267
+ attach_function :rcl_node_fini, [RclNodeT.by_ref], RclRetT
268
+ attach_function :rcl_node_get_default_options, [], RclNodeOptionsT.by_value
269
+ attach_function :rcl_node_get_namespace, [RclNodeT.by_ref], :string
270
+
271
+ # Subscription API
272
+ attach_function :rcl_get_zero_initialized_subscription, [], RclSubscriptionT.by_value
273
+ attach_function :rcl_subscription_get_default_options, [], RclSubscriptionOptionsT.by_value
274
+ attach_function :rcl_subscription_init, [RclSubscriptionT.by_ref, RclNodeT.by_ref, RosidlMessageTypeSupportT.by_ref, :string, RclSubscriptionOptionsT.by_ref], RclRetT
275
+ attach_function :rcl_subscription_fini, [RclSubscriptionT.by_ref, RclNodeT.by_ref], RclRetT
276
+ attach_function :rcl_take, [RclSubscriptionT.by_ref, :pointer, RmwMessageInfoT.by_ref, RmwSubscriptionAllocationT.by_ref], RclRetT
277
+
278
+ # Publisher API
279
+ attach_function :rcl_get_zero_initialized_publisher, [], RclPublisherT.by_value
280
+ attach_function :rcl_publisher_get_default_options, [], RclPublisherOptionsT.by_value
281
+ attach_function :rcl_publisher_init, [RclPublisherT.by_ref, RclNodeT.by_ref, RosidlMessageTypeSupportT.by_ref, :string, RclPublisherOptionsT.by_ref], RclRetT
282
+ attach_function :rcl_publisher_fini, [RclPublisherT.by_ref, RclNodeT.by_ref], RclRetT
283
+ attach_function :rcl_publish, [RclPublisherT.by_ref, :pointer, RmwPublisherAllocationT.by_ref], RclRetT
284
+ attach_function :rcl_publisher_get_subscription_count, [RclPublisherT.by_ref, SizeTPtr.by_ref], RclRetT
285
+
286
+ # Service API
287
+ attach_function :rcl_get_zero_initialized_service, [], RclServiceT.by_value
288
+ attach_function :rcl_service_get_default_options, [], RclServiceOptionsT.by_value
289
+ attach_function :rcl_service_init, [RclServiceT.by_ref, RclNodeT.by_ref, RosidlServiceTypeSupportT.by_ref, :string, RclServiceOptionsT.by_ref], RclRetT
290
+ attach_function :rcl_service_fini, [RclServiceT.by_ref, RclNodeT.by_ref], RclRetT
291
+ attach_function :rcl_take_request, [RclServiceT.by_ref, RmwRequestIdT.by_ref, :pointer], RclRetT
292
+ attach_function :rcl_send_response, [RclServiceT.by_ref, RmwRequestIdT.by_ref, :pointer], RclRetT
293
+
294
+ # Client API
295
+ attach_function :rcl_get_zero_initialized_client, [], RclClientT.by_value
296
+ attach_function :rcl_client_get_default_options, [], RclClientOptionsT.by_value
297
+ attach_function :rcl_client_init, [RclClientT.by_ref, RclNodeT.by_ref, RosidlServiceTypeSupportT.by_ref, :string, RclClientOptionsT.by_ref], RclRetT
298
+ attach_function :rcl_client_fini, [RclClientT.by_ref, RclNodeT.by_ref], RclRetT
299
+ attach_function :rcl_send_request, [RclClientT.by_ref, :pointer, Int64Ptr.by_ref], RclRetT
300
+ attach_function :rcl_take_response_with_info, [RclClientT.by_ref, RmwServiceInfoT.by_ref, :pointer], RclRetT
301
+
302
+ # GuardCondition API
303
+ attach_function :rcl_get_zero_initialized_guard_condition, [], RclGuardConditionT.by_value
304
+ attach_function :rcl_guard_condition_init, [RclGuardConditionT.by_ref, RclContextT.by_ref, RclGuardConditionOptionsT.by_value], RclRetT
305
+ attach_function :rcl_guard_condition_get_default_options, [], RclGuardConditionOptionsT.by_value
306
+ attach_function :rcl_trigger_guard_condition, [RclGuardConditionT.by_ref], RclRetT
307
+
308
+ # Clock API
309
+ attach_function :rcl_clock_init, [:RclClockTypeT, RclClockT.by_ref, RclAllocatorT.by_ref], RclRetT
310
+
311
+ # Timer API
312
+ attach_function :rcl_get_zero_initialized_timer, [], RclTimerT.by_value
313
+ callback :timer_callback, [RclTimerT.by_ref, :int64], :void
314
+ attach_function :rcl_timer_init, [RclTimerT.by_ref, RclClockT.by_ref, RclContextT.by_ref, :int64, :timer_callback, RclAllocatorT.by_value], RclRetT
315
+ attach_function :rcl_timer_fini, [RclTimerT.by_ref, RclNodeT.by_ref], RclRetT
316
+ attach_function :rcl_timer_call, [RclTimerT.by_ref], RclRetT
317
+ attach_function :rcl_timer_is_ready, [RclTimerT.by_ref, BoolPtr.by_ref], RclRetT
318
+
319
+ # WaitSet API
320
+ attach_function :rcl_get_zero_initialized_wait_set, [], RclWaitSetT.by_value
321
+ attach_function :rcl_wait_set_init, [RclWaitSetT.by_ref, :size_t, :size_t, :size_t, :size_t, :size_t, :size_t, RclContextT.by_ref, RclAllocatorT.by_value], RclRetT
322
+ attach_function :rcl_wait_set_fini, [RclWaitSetT.by_ref], RclRetT
323
+ attach_function :rcl_wait, [RclWaitSetT.by_ref, :int64], RclRetT, blocking: true
324
+ attach_function :rcl_wait_set_add_subscription, [RclWaitSetT.by_ref, RclSubscriptionT.by_ref, SizeTPtr.by_ref], RclRetT
325
+ attach_function :rcl_wait_set_add_guard_condition, [RclWaitSetT.by_ref, RclGuardConditionT.by_ref, SizeTPtr.by_ref], RclRetT
326
+ attach_function :rcl_wait_set_add_timer, [RclWaitSetT.by_ref, RclTimerT.by_ref, SizeTPtr.by_ref], RclRetT
327
+ attach_function :rcl_wait_set_add_client, [RclWaitSetT.by_ref, RclClientT.by_ref, SizeTPtr.by_ref], RclRetT
328
+ attach_function :rcl_wait_set_add_service, [RclWaitSetT.by_ref, RclServiceT.by_ref, SizeTPtr.by_ref], RclRetT
329
+
330
+ # Graph API
331
+ attach_function :rcl_service_server_is_available, [RclNodeT.by_ref, RclClientT.by_ref, BoolPtr.by_ref], RclRetT
332
+
333
+ # rcutils API
334
+ attach_function :rcutils_get_default_allocator, [], RclAllocatorT.by_value
335
+ attach_function :rcutils_get_error_string, [], RcutilsErrorStringT.by_value
336
+ attach_function :rcutils_reset_error, [], :void
337
+
338
+ def CApi.create_type_support_library(module_name, package_name, longtype, shorttype, idltype, messages)
339
+ template = ERB.new <<-EOF
340
+ module <%= module_name %>
341
+ module TypeSupportCApi
342
+ extend FFI::Library
343
+ ffi_lib '<%= package_name %>__rosidl_typesupport_c'
344
+ <% messages.each() do | m | %>
345
+ attach_function :rosidl_typesupport_c__get_#{longtype}_type_support_handle__<%= package_name %>__#{shorttype}__<%= m %>, [], CApi::#{idltype}.by_ref
346
+ TypeSupport_#{shorttype}_<%= m %> = rosidl_typesupport_c__get_#{longtype}_type_support_handle__<%= package_name %>__#{shorttype}__<%= m %>
347
+ <% end %>
348
+ end
349
+ end
350
+ EOF
351
+ Object.class_eval template.result(binding)
352
+ end
353
+
354
+ def CApi.create_node()
355
+ return CApi::RclNodeT.new()
356
+ end
357
+ def CApi.get_error_string()
358
+ msg = CApi.rcutils_get_error_string()[:str]
359
+ CApi.rcutils_reset_error();
360
+ return msg
361
+ end
362
+ def CApi.handle_result(ret, always_call = nil)
363
+ always_call.call if always_call
364
+ if ret != RCL_RET_OK
365
+ raise RclError.new "Error #{ret.to_i}: #{CApi.get_error_string()}"
366
+ end
367
+ end
368
+ end
369
+ end
@@ -0,0 +1,79 @@
1
+ module Rclrb
2
+ ##
3
+ # Represent a ROS client
4
+ class Client
5
+ attr_reader :srv_type, :client_handle
6
+ # Construct a new publisher, this should not be called directly, instead use Node.create_publisher.
7
+ def initialize(client_handle, node_handle, srv_type, srv_name, qos_profile)
8
+ @client_handle = client_handle
9
+ @node_handle = node_handle
10
+ @srv_type = srv_type
11
+ @srv_name = srv_name
12
+ @qos_profile = qos_profile
13
+ @call_counter = 0
14
+
15
+ client_ops = CApi.rcl_client_get_default_options()
16
+ client_ops[:qos] = QoSProfile.get_profile(qos_profile).ros_profile
17
+ CApi.handle_result CApi.rcl_client_init(@client_handle, node_handle, srv_type.type_support(), @srv_name, client_ops)
18
+ end
19
+
20
+ rclrb_finalize_with :@client_handle, :@node_handle do |client_handle, node_handle|
21
+ CApi.handle_result CApi.rcl_client_fini client_handle, node_handle
22
+ end
23
+
24
+ ##
25
+ # Call a service asynchronously with the given +request+, it will return a Future object.
26
+ def call_async(request)
27
+ raise RclError.new unless request.kind_of? @srv_type::Request
28
+
29
+ counter = CApi::Int64Ptr.new
30
+ counter[:value] = (@call_counter += 1)
31
+ future = Future.execute do
32
+ ros_req = @srv_type::Request.get_ros_message request
33
+ CApi.handle_result CApi.rcl_send_request(@client_handle, ros_req, counter), lambda { @srv_type::Request.destroy_ros_message(ros_req)}
34
+ ros_resp = @srv_type::Response::FFIType.new
35
+ info = CApi::RmwServiceInfoT.new
36
+ waiting_for_answer = true
37
+ wait_set = WaitSet.new
38
+ wait_set.add self
39
+ while waiting_for_answer
40
+ wait_set.wait
41
+ status = CApi.rcl_take_response_with_info @client_handle, info, ros_resp
42
+ if status == CApi::RCL_RET_OK
43
+ response = @srv_type::Response.parse_ros_message ros_resp
44
+ @srv_type::Response.destroy_ros_message ros_resp
45
+ waiting_for_answer = false
46
+ elsif status == CApi::RCL_RET_CLIENT_TAKE_FAILED
47
+ raise ServiceCallFailed.new
48
+ else
49
+ CApi.handle_result status
50
+ end
51
+ if Rclrb.rcl_shutdown_requested?
52
+ raise InterruptedClientCall.new "Call to #{@srv_name} was interrupted by shutdown"
53
+ end
54
+ end
55
+ response
56
+ end
57
+ return future
58
+ end
59
+ ##
60
+ # Wait for the service to be available. If +timeout_sec+ is nil, it will wait forever, otherwise it will timeout when
61
+ # the amount of time specified by +timeout_sec+ has expired.
62
+ def wait_for_service(timeout_sec=nil)
63
+ sleep_time = 0.25
64
+ timeout_sec = Float::INFINITY if timeout_sec.nil?
65
+ until Rclrb.rcl_shutdown_requested? or self.service_is_ready() or timeout_sec < 0.0
66
+ sleep(sleep_time)
67
+ timeout_sec -= sleep_time
68
+ end
69
+ return self.service_is_ready
70
+ end
71
+ # Return true if the service is available.
72
+ def service_is_ready
73
+ b = CApi::BoolPtr.new
74
+ CApi.handle_result CApi.rcl_service_server_is_available @node_handle, @client_handle, b
75
+ return b[:value]
76
+ end
77
+ end
78
+ end
79
+
@@ -0,0 +1,17 @@
1
+ module Rclrb
2
+ ##
3
+ # Represent a clock, instead of creating directly, use RosClock or SystemClock
4
+ class Clock
5
+ attr_reader :handle
6
+ def initialize(type)
7
+ @handle = CApi::RclClockT.new
8
+ CApi.handle_result(CApi.rcl_clock_init(type, @handle, CApi.rcutils_get_default_allocator()))
9
+ end
10
+ end
11
+ ##
12
+ # Represent a clock with Ros time (either system or simulated time)
13
+ RosClock = Clock.new(:RCL_ROS_TIME)
14
+ ##
15
+ # Represent a clock that is always set to system time
16
+ SystemClock = Clock.new(:RCL_SYSTEM_TIME)
17
+ end
@@ -0,0 +1,43 @@
1
+
2
+ def Object.rclrb_finalize_with *ivars_names, &block
3
+ old_init = instance_method :initialize
4
+
5
+ define_method :initialize do |*args|
6
+ old_init.bind(self).call *args
7
+ ivars = ivars_names.map { |ivar| instance_variable_get(ivar) }
8
+ ObjectSpace.define_finalizer self, Object.rclrb_create_finalizer(block, ivars)
9
+ end
10
+ private_class_method def Object.rclrb_create_finalizer block, ivars
11
+ return proc { block.call(*ivars) }
12
+ end
13
+ end
14
+
15
+ module Rclrb
16
+ ##
17
+ # Base class for any exception triggered by Rclrb
18
+ class Error < StandardError
19
+ end
20
+ ##
21
+ # An unhandled error occured in the Rcl library. This is generally indicative of a bug in Rclrb.
22
+ class RclError < Error
23
+ end
24
+ ##
25
+ # An error occured while parsing a message, service or action definiton.
26
+ class ParseError < Error
27
+ end
28
+ ##
29
+ # A call to service was interrupted
30
+ class InterruptedClientCall < Error
31
+ end
32
+ ##
33
+ # Failed to get answer to a service call
34
+ class ServiceCallFailed < Error
35
+ end
36
+ ##
37
+ # Publisher.call or Client.call was called with the wrong type of message.
38
+ class InvalidMessageTypeError < Error
39
+ def initialize got, expected
40
+ super "Invalid message type got '#{got}' expected '#{expected}"
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,34 @@
1
+ module Rclrb
2
+ ##
3
+ # An executor controls the threading model used to process callbacks. Callbacks are units of work
4
+ # like subscription callbacks, timer callbacks, and service calls. An executor controls which threads
5
+ # callbacks get executed in.
6
+ class Executor
7
+ def initialize(*nodes)
8
+ @nodes = nodes
9
+ @groups = nodes.map { |x| x.default_callback_group }
10
+ end
11
+ ##
12
+ # Add a node to the executor
13
+ def add_node(node)
14
+ @nodes.append node
15
+ @groups.append node.default_callback_group
16
+ end
17
+ ##
18
+ # Spin continuously untill shutdown was requested
19
+ def spin()
20
+ until Rclrb.rcl_shutdown_requested?
21
+ wait_set = WaitSet.new
22
+ threads = @groups.map { |g| g.spin wait_set }
23
+ threads.each { |t| t.join }
24
+ wait_set.wait
25
+ end
26
+ end
27
+ end
28
+ ##
29
+ # Spin the given nodes using Executor
30
+ def Rclrb.spin(*nodes)
31
+ e = Executor.new *nodes
32
+ return e.spin
33
+ end
34
+ end