rclrb 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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