rclrb 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/COPYING +373 -0
- data/README.md +13 -0
- data/lib/rclrb/callback_group.rb +31 -0
- data/lib/rclrb/capi.rb +369 -0
- data/lib/rclrb/client.rb +79 -0
- data/lib/rclrb/clock.rb +17 -0
- data/lib/rclrb/common.rb +43 -0
- data/lib/rclrb/executor.rb +34 -0
- data/lib/rclrb/fields.rb +224 -0
- data/lib/rclrb/future.rb +82 -0
- data/lib/rclrb/guard_condition.rb +18 -0
- data/lib/rclrb/init.rb +59 -0
- data/lib/rclrb/interfaces.rb +270 -0
- data/lib/rclrb/internal.rb +16 -0
- data/lib/rclrb/node.rb +143 -0
- data/lib/rclrb/publisher.rb +40 -0
- data/lib/rclrb/qos.rb +116 -0
- data/lib/rclrb/service.rb +46 -0
- data/lib/rclrb/subscription.rb +45 -0
- data/lib/rclrb/time.rb +32 -0
- data/lib/rclrb/timer.rb +31 -0
- data/lib/rclrb/version.rb +3 -0
- data/lib/rclrb/wait_set.rb +62 -0
- data/lib/rclrb.rb +43 -0
- metadata +98 -0
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
|
data/lib/rclrb/client.rb
ADDED
@@ -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
|
+
|
data/lib/rclrb/clock.rb
ADDED
@@ -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
|
data/lib/rclrb/common.rb
ADDED
@@ -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
|