Class: OroGen::TypekitMarshallers::ROS::Plugin
- Inherits:
-
Object
- Object
- OroGen::TypekitMarshallers::ROS::Plugin
- Defined in:
- lib/orogen/marshallers/ros.rb
Overview
Typekit generation plugin to handle ROS types
Constant Summary collapse
- ARRAY_TYPES =
[Typelib::ContainerType, Typelib::ArrayType]
Instance Attribute Summary collapse
-
#boxed_msg_mappings ⇒ Object
readonly
Mappings from ROS boxed messages to the base type they are wrapping.
-
#type_to_msg ⇒ Object
readonly
Mappings from oroGen types to ROS message names.
-
#typekit ⇒ Object
readonly
The underlying typekit.
Class Method Summary collapse
Instance Method Summary collapse
-
#boxed_ros_msg?(msg_name) ⇒ Boolean
Checks whether a ROS message name is a boxing type.
-
#dependencies ⇒ Object
Generates the set of compilation dependencies for the ROS transport.
-
#enabled=(value) ⇒ Boolean
True if the plugin is enabled, i.e.
-
#enabled? ⇒ Boolean
True if the plugin is enabled, i.e.
-
#generate(typesets) ⇒ Object
Do the code generation for this ROS transport.
- #generate_disabled(typesets, convert_types, convert_array_types, user_converted_types) ⇒ Object
- #generate_type_convertion_list(typeset) ⇒ Object
-
#has_custom_convertions? ⇒ Boolean
True if some custom oroGen-to-ROS convertions have been registered.
-
#initialize(typekit) ⇒ Plugin
constructor
A new instance of Plugin.
- #load_ros_mappings ⇒ Object
- #multidimensional_array?(type) ⇒ Boolean
- #name ⇒ Object
-
#ros_arg_type(type, unbox = true) ⇒ Object
Returns the argument signature the C++ type for the ROS message that represents
type
. -
#ros_base_type?(type) ⇒ Boolean
Returns true if
type
is a base type in ROS. -
#ros_converted_type?(type) ⇒ Boolean
Returns whether
type
should be exported as a ROS message. -
#ros_cxx_type(type, do_unboxing = true) ⇒ Object
Returns the C++ type name for the ROS message that represents
type
. -
#ros_exported_type?(type) ⇒ Boolean
Returns whether
type
should be exported as a ROS message. -
#ros_field_name(type, absolute = false) ⇒ Object
Returns the type name that should be used in a field in another ROS message.
-
#ros_mappings(mappings) ⇒ Object
Define custom mappings from typegen types to ROS messages.
-
#ros_message_name(type, absolute = false) ⇒ Object
Returns the ROS message name for
type
. -
#ros_package_name_for_typekit(typekit) ⇒ String
Returns the ROS package name generated for a given typekit.
-
#ros_ref_type(type, unbox = true) ⇒ Object
Returns a reference signature to the C++ type for the ROS message that represents
type
. -
#separate_cmake? ⇒ Boolean
Generates the set of compilation dependencies for the ROS transport.
Constructor Details
#initialize(typekit) ⇒ Plugin
Returns a new instance of Plugin
75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/orogen/marshallers/ros.rb', line 75 def initialize(typekit) @typekit = typekit @type_to_msg = DEFAULT_TYPE_TO_MSG.dup @boxed_msg_mappings = DEFAULT_BOXED_MSG_MAPPINGS.dup self.enabled = true Typelib::Type.extend TypeExtension Typelib::OpaqueType.extend OpaqueTypeExtension Typelib::ContainerType.extend ContainerTypeExtension Typelib::ArrayType.extend ArrayTypeExtension Typelib::CompoundType.extend CompoundTypeExtension end |
Instance Attribute Details
#boxed_msg_mappings ⇒ Object (readonly)
Mappings from ROS boxed messages to the base type they are wrapping
Base ROS types cannot be used as messages. One has to first box them into a std_msgs message. This registers these mappings. oroGen then always generate a convertion function for the boxed type whenever the type_to_msg specify a message that should be boxed.
107 108 109 |
# File 'lib/orogen/marshallers/ros.rb', line 107 def boxed_msg_mappings @boxed_msg_mappings end |
#type_to_msg ⇒ Object (readonly)
Mappings from oroGen types to ROS message names
95 96 97 |
# File 'lib/orogen/marshallers/ros.rb', line 95 def type_to_msg @type_to_msg end |
#typekit ⇒ Object (readonly)
The underlying typekit
182 183 184 |
# File 'lib/orogen/marshallers/ros.rb', line 182 def typekit @typekit end |
Class Method Details
.name ⇒ Object
72 |
# File 'lib/orogen/marshallers/ros.rb', line 72 def self.name; "ros" end |
Instance Method Details
#boxed_ros_msg?(msg_name) ⇒ Boolean
Checks whether a ROS message name is a boxing type
116 117 118 |
# File 'lib/orogen/marshallers/ros.rb', line 116 def boxed_ros_msg?(msg_name) !!boxed_msg_mappings[msg_name] end |
#dependencies ⇒ Object
Generates the set of compilation dependencies for the ROS transport
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/orogen/marshallers/ros.rb', line 149 def dependencies result = [] typekit.used_typekits.each do |tk| next if tk.virtual? build_dep = Gen::RTT_CPP::BuildDependency.new( tk.name.upcase + "_TRANSPORT_ROS", tk.pkg_transport_name('ros')) build_dep.in_context('ros', 'include') build_dep.in_context('ros', 'link') result << build_dep end typekit.used_libraries.each do |pkg| needs_link = typekit.linked_used_libraries.include?(pkg) result << Gen::RTT_CPP::BuildDependency.new(pkg.name.upcase, pkg.name). in_context('ros', 'include') if needs_link result.last.in_context('ros', 'link') end end build_dep = Gen::RTT_CPP::BuildDependency.new( "OROCOS_RTT_ROS", "orocos-rtt-ros-${OROCOS_TARGET}") build_dep.in_context('ros', 'include') build_dep.in_context('ros', 'link') result << build_dep result end |
#enabled=(value) ⇒ Boolean
Returns true if the plugin is enabled, i.e. if the transport should be generated
90 |
# File 'lib/orogen/marshallers/ros.rb', line 90 attr_predicate :enabled?, true |
#enabled? ⇒ Boolean
Returns true if the plugin is enabled, i.e. if the transport should be generated
90 |
# File 'lib/orogen/marshallers/ros.rb', line 90 attr_predicate :enabled?, true |
#generate(typesets) ⇒ Object
Do the code generation for this ROS transport
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 |
# File 'lib/orogen/marshallers/ros.rb', line 359 def generate(typesets) load_ros_mappings @typekit = typekit rosmsg_registry = typesets.minimal_registry.dup # All the generated messages. Used to generate the CMake # file = Array.new typesets.converted_types.each do |type| # We are reusing an existing ROS message next if type_to_msg.has_key?(type.name) type_name = type.name msg_name = (type) if ros_exported_type?(type) && !typekit.m_type?(type) if type.opaque? type = typekit.intermediate_type_for(type) end msg = Gen::RTT_CPP.render_template "typekit", "ros", "Type.msg", binding typekit.save_automatic("transports", "ros", "msg", "#{msg_name}.msg", msg) << msg_name end end = .sort convert_types = generate_type_convertion_list( typesets.converted_types. find_all { |t| !type_to_msg[t.name] && !typekit.m_type?(t)}) convert_array_types = generate_type_convertion_list( typesets.array_types.map(&:deference). find_all { |t| !typekit.m_type?(t)}) user_converted_types = generate_type_convertion_list( typesets.converted_types. find_all { |t| type_to_msg[t.name] }) user_converted_types.delete_if do |type, ros_type| ros_cxx_type(type) == type.cxx_name.gsub(/^::/, '') end if !enabled? return generate_disabled(typesets, convert_types, convert_array_types, user_converted_types) end # Have a look the user_converted_types whether we need to # generate some unboxing functions automatically convert_boxed_types = user_converted_types.find_all do |type, ros_type| boxed_ros_msg?((ros_type, true)) end.to_set rejected = [] code_snippets = typesets.interface_types.map do |type| if !ros_exported_type?(type) rejected << type next end if (mapped = type_to_msg[type.name]) && boxed_ros_msg?(mapped) convert_boxed_types << [type, type] end code = Gen::RTT_CPP.render_template "typekit", "ros", "Type.cpp", binding [type, code] end.compact headers, impl = Array.new, Array.new convert_boxed_types = convert_boxed_types.sort_by { |t1, t2| [t1.name, t2.name] } code = Gen::RTT_CPP.render_template "typekit", "ros", "Convertions.hpp", binding headers << typekit.save_automatic("transports", "ros", "Convertions.hpp", code) code = Gen::RTT_CPP.render_template "typekit", "ros", "Convertions.cpp", binding impl << typekit.save_automatic("transports", "ros", "Convertions.cpp", code) code = Gen::RTT_CPP.render_template "typekit", "ros", "TransportPlugin.hpp", binding headers << typekit.save_automatic("transports", "ros", "TransportPlugin.hpp", code) code = Gen::RTT_CPP.render_template "typekit", "ros", "TransportPlugin.cpp", binding impl << typekit.save_automatic("transports", "ros", "TransportPlugin.cpp", code) if !user_converted_types.empty? # We need to generate a user part with the convertion # functions. Reuse the templates ! code = Gen::RTT_CPP.render_template "typekit", "ros", "ROSConvertions.hpp", binding headers << typekit.save_user("ROSConvertions.hpp", code) code = Gen::RTT_CPP.render_template "typekit", "ros", "ROSConvertions.cpp", binding impl << typekit.save_user("ROSConvertions.cpp", code) Gen::RTT_CPP.create_or_update_symlink( headers.last, File.join(typekit.automatic_dir, "transports", "ros", "ROSConvertions.hpp")) end impl += typekit.render_typeinfo_snippets(code_snippets, "transports", "ros") if !rejected.empty? ROS.warn "#{rejected.size} types cannot be exported to ROS, you will not able to publish/subscribe ports of these types to/from ROS: #{rejected.map(&:name).sort.join(", ")}" end code = Gen::RTT_CPP.render_template "typekit", "ros", "Registration.hpp", binding typekit.save_automatic("transports", "ros", "Registration.hpp", code) impl = impl.map do |path| typekit.cmake_relative_path(path, "transports", "ros") end.sort headers = headers.map do |path| typekit.cmake_relative_path(path, "transports", "ros") end.sort cmake_config = Gen::RTT_CPP.render_template "typekit", "ros", "config.cmake.in", binding typekit.save_automatic("transports", "ros", "orogen_#{typekit.name}_msgs-config.cmake.in", cmake_config) rosmap = Gen::RTT_CPP.render_template "typekit", "ros", "rosmap", binding rosmap = typekit.save_automatic("transports", "ros", "#{typekit.name}.rosmap", rosmap) pkg_config = Gen::RTT_CPP.render_template "typekit", "ros", "transport-ros.pc", binding typekit.save_automatic("transports", "ros", "#{typekit.name}-transport-ros.pc.in", pkg_config) cmake = Gen::RTT_CPP.render_template "typekit", "ros", "CMakeLists.txt", binding typekit.save_automatic("transports", "ros", "CMakeLists.txt", cmake) return [], [] end |
#generate_disabled(typesets, convert_types, convert_array_types, user_converted_types) ⇒ Object
346 347 348 349 350 351 352 353 354 355 356 |
# File 'lib/orogen/marshallers/ros.rb', line 346 def generate_disabled(typesets, convert_types, convert_array_types, user_converted_types) rosmap = Gen::RTT_CPP.render_template "typekit", "ros", "rosmap", binding rosmap = typekit.save_automatic("transports", "ros", "#{typekit.name}.rosmap", rosmap) pkg_config = Gen::RTT_CPP.render_template "typekit", "ros", "transport-ros-disabled.pc", binding typekit.save_automatic("transports", "ros", "#{typekit.name}-transport-ros.pc.in", pkg_config) cmake = Gen::RTT_CPP.render_template "typekit", "ros", "CMakeLists-disabled.txt", binding typekit.save_automatic("transports", "ros", "CMakeLists.txt", cmake) return [], [] end |
#generate_type_convertion_list(typeset) ⇒ Object
332 333 334 335 336 337 338 339 340 341 342 343 344 |
# File 'lib/orogen/marshallers/ros.rb', line 332 def generate_type_convertion_list(typeset) convert_types = Array.new typeset.each do |type| next if !ros_converted_type?(type) convert_types << [type, type] target_type = typekit.intermediate_type_for(type) if target_type != type convert_types << [target_type, type] end end convert_types.to_set.to_a.sort_by { |t0, t1| [t0.name, t1.name] } end |
#has_custom_convertions? ⇒ Boolean
True if some custom oroGen-to-ROS convertions have been registered
111 112 113 |
# File 'lib/orogen/marshallers/ros.rb', line 111 def has_custom_convertions? !type_to_msg.empty? end |
#load_ros_mappings ⇒ Object
133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/orogen/marshallers/ros.rb', line 133 def load_ros_mappings typekit.used_typekits.each do |tk| next if tk.virtual? begin # Yuk ! Not dependent on the architecture, and # hardcoded pkg-config stuff behaviour raw_mapping = ROS.load_rosmap_by_package_name(tk.name) raw_mapping.delete_if { |type_name, _| !typekit.registry.include?(type_name) } ros_mappings(raw_mapping) rescue Utilrb::PkgConfig::NotFound end end end |
#multidimensional_array?(type) ⇒ Boolean
295 296 297 298 |
# File 'lib/orogen/marshallers/ros.rb', line 295 def multidimensional_array?(type) ARRAY_TYPES.any? { |array_t| type < array_t } && ARRAY_TYPES.any? { |array_t| type.deference < array_t } end |
#name ⇒ Object
73 |
# File 'lib/orogen/marshallers/ros.rb', line 73 def name; "ros" end |
#ros_arg_type(type, unbox = true) ⇒ Object
Returns the argument signature the C++ type for the ROS message that
represents type
289 290 291 |
# File 'lib/orogen/marshallers/ros.rb', line 289 def ros_arg_type(type, unbox = true) "#{ros_cxx_type(type, unbox)} const&" end |
#ros_base_type?(type) ⇒ Boolean
Returns true if type
is a base type in ROS
185 186 187 |
# File 'lib/orogen/marshallers/ros.rb', line 185 def ros_base_type?(type) type < Typelib::NumericType || type < Typelib::EnumType end |
#ros_converted_type?(type) ⇒ Boolean
Returns whether type
should be exported as a ROS message
301 302 303 304 305 306 307 308 309 310 311 312 313 314 |
# File 'lib/orogen/marshallers/ros.rb', line 301 def ros_converted_type?(type) type = typekit.intermediate_type_for(type) return true if type_to_msg.has_key?(type.name) return if ros_base_type?(type) if type < Typelib::CompoundType ros_exported_type?(type) elsif multidimensional_array?(type) return false elsif ARRAY_TYPES.any? { |array_type| type < array_type } return (ros_converted_type?(type.deference) || type.deference <= Typelib::EnumType) else true end end |
#ros_cxx_type(type, do_unboxing = true) ⇒ Object
Returns the C++ type name for the ROS message that represents
type
unboxed version of the message (i.e. std_msgs/Time would map to ros::Time). If false, the base message type name is kept
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/orogen/marshallers/ros.rb', line 248 def ros_cxx_type(type, do_unboxing = true) explicit_mapping = type_to_msg[type.name] if !explicit_mapping && (type < Typelib::ArrayType || type < Typelib::ContainerType) return "std::vector< #{ros_cxx_type(type.deference, do_unboxing)} >" end msg_name = (type, true) if do_unboxing && (unboxed = boxed_msg_mappings[msg_name]) msg_name = unboxed end if type < Typelib::NumericType && do_unboxing if type.integer? if msg_name == "bool" then "bool" else "boost::#{msg_name}_t" end elsif type.size == 4 return "float" elsif type.size == 8 return "double" else raise ArgumentError, "don't know what to use to represent #{type} on the ROS C++ mapping" end elsif type < Typelib::EnumType return "boost::int32_t" elsif msg_name == "time" return "ros::Time" elsif msg_name == 'string' return 'std::string' else return msg_name.gsub(/\//, '::') end end |
#ros_exported_type?(type) ⇒ Boolean
Returns whether type
should be exported as a ROS message
317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
# File 'lib/orogen/marshallers/ros.rb', line 317 def ros_exported_type?(type) type = typekit.intermediate_type_for(type) return true if type_to_msg.has_key?(type.name) return if ros_base_type?(type) return if !(type < Typelib::CompoundType) # ROS cannot represent arrays in arrays. Filter those out type.recursive_dependencies.each do |t| next if type_to_msg.has_key?(t.name) if multidimensional_array?(t) return end end return true end |
#ros_field_name(type, absolute = false) ⇒ Object
Returns the type name that should be used in a field in another ROS message
For “normal” messages, this is the message name. For boxed messages (e.g. std_msgs/Time), it is the corresponding base type
195 196 197 198 199 200 201 202 |
# File 'lib/orogen/marshallers/ros.rb', line 195 def ros_field_name(type, absolute = false) if !type_to_msg.has_key?(type.name) && (type <= Typelib::ArrayType || type <= Typelib::ContainerType) "#{ros_field_name(type.deference, absolute)}[]" else msg_name = (type, absolute) boxed_msg_mappings[msg_name] || msg_name end end |
#ros_mappings(mappings) ⇒ Object
Define custom mappings from typegen types to ROS messages
known to oroGen to the ROS message that should be used to represent it on the ROS side. The ROS message name should be fully qualified
126 127 128 129 130 131 |
# File 'lib/orogen/marshallers/ros.rb', line 126 def ros_mappings(mappings) mappings.each do |typename, ros_msg_name| type = typekit.find_type(typename) type_to_msg[type.name] = ros_msg_name end end |
#ros_message_name(type, absolute = false) ⇒ Object
Returns the ROS message name for type
always contain its namespace. Otherwise, it contains its namespace only if
not generated by typekit
. This is required by the ROS message
generator
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/orogen/marshallers/ros.rb', line 222 def (type, absolute = false) if type < Typelib::EnumType "std_msgs/Int32" elsif msg_name = type_to_msg[type.name] return msg_name elsif type <= Typelib::ArrayType || type <= Typelib::ContainerType "#{(type.deference, absolute)}[]" else source_typekit = typekit.imported_typekits_for(type.name).first if source_typekit || absolute prefix = "#{ros_package_name_for_typekit(source_typekit || typekit)}/" end "#{prefix}" + type.name. split("/"). map { |n| "#{n[0, 1].upcase}#{n[1..-1]}" }. join(""). gsub(/[^\w]/, "") end end |
#ros_package_name_for_typekit(typekit) ⇒ String
Returns the ROS package name generated for a given typekit
208 209 210 211 212 213 |
# File 'lib/orogen/marshallers/ros.rb', line 208 def ros_package_name_for_typekit(typekit) if typekit.respond_to?(:name) typekit = typekit.name end "orogen_#{typekit}_msgs" end |
#ros_ref_type(type, unbox = true) ⇒ Object
Returns a reference signature to the C++ type for the ROS message that
represents type
283 284 285 |
# File 'lib/orogen/marshallers/ros.rb', line 283 def ros_ref_type(type, unbox = true) "#{ros_cxx_type(type, unbox)}&" end |
#separate_cmake? ⇒ Boolean
Generates the set of compilation dependencies for the ROS transport
179 |
# File 'lib/orogen/marshallers/ros.rb', line 179 def separate_cmake?; true end |