Class: Syskit::Robot::RobotDefinition
- Includes:
- MetaRuby::DSLs::FindThroughMethodMissing
- Defined in:
- lib/syskit/robot/robot_definition.rb
Overview
RobotDefinition objects describe a robot through the devices that are available on it.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#devices ⇒ Object
readonly
The devices that are available on this robot.
Instance Method Summary collapse
- #clear ⇒ Object
-
#com_bus(type, options = Hash.new) ⇒ Object
Declares a new communication bus.
-
#device(device_model, doc: nil, **options) ⇒ Object
Adds a new device to this robot definition.
- #each_device(&block) ⇒ Object
-
#each_master_device ⇒ Object
Enumerates all master devices that are available on this robot.
-
#each_slave_device ⇒ Object
Enumerates all slave devices that are available on this robot.
- #empty? ⇒ Boolean
-
#find_device(name) ⇒ DeviceInstance?
Returns a device by its name.
- #find_through_method_missing(m, args) ⇒ Object
-
#has_device?(name) ⇒ Boolean
Returns true if
name
is the name of a device registered on this robot model. - #has_through_method_missing?(m) ⇒ Boolean
-
#initialize ⇒ RobotDefinition
constructor
A new instance of RobotDefinition.
-
#inject_di_context(requirements) ⇒ Object
Modify the raw requirements to add context information.
- #invalidate_dependency_injection ⇒ Object
- #register_device(name, device_instance) ⇒ Object
-
#through(com_bus, &block) ⇒ Object
Makes all devices declared in the provided block are using the given bus.
-
#to_dependency_injection ⇒ Object
Returns a dependency injection object that maps names to devices.
-
#use_robot(robot) ⇒ Object
Add the devices defined in the given robot to the ones defined in self.
Constructor Details
#initialize ⇒ RobotDefinition
Returns a new instance of RobotDefinition
6 7 8 |
# File 'lib/syskit/robot/robot_definition.rb', line 6 def initialize @devices = Hash.new end |
Instance Attribute Details
#devices ⇒ Object (readonly)
The devices that are available on this robot
11 12 13 |
# File 'lib/syskit/robot/robot_definition.rb', line 11 def devices @devices end |
Instance Method Details
#clear ⇒ Object
21 22 23 24 |
# File 'lib/syskit/robot/robot_definition.rb', line 21 def clear invalidate_dependency_injection devices.clear end |
#com_bus(type, options = Hash.new) ⇒ Object
Declares a new communication bus
61 62 63 |
# File 'lib/syskit/robot/robot_definition.rb', line 61 def com_bus(type, = Hash.new) device(type, .merge(expected_model: Syskit::ComBus, class: ComBus)) end |
#device(device_model, doc: nil, **options) ⇒ Object
Adds a new device to this robot definition.
device_model
is either the device type or its name. It is
implicitely declared by the use of driver_for in component classes, or by
using SystemModel#device_type.
For instance, if a Hokuyo orogen component is available that can drive Hokuyo laser scanners, then one would declare the driver with:
class Hokuyo
driver_for 'Devices::Hokuyo'
end
the newly declared device type can then be accessed as a constant with Devices::Hokuyo. I.e.
Devices::Hokuyo
is the subclass of DeviceModel that describes this device type. It can then be used to declare devices on a robot with
Robot.devices do
device Devices::Hokuyo
end
This method returns the MasterDeviceInstance instance that describes the actual device
135 136 137 138 139 140 141 142 143 144 145 146 147 148 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 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/syskit/robot/robot_definition.rb', line 135 def device(device_model, doc: nil, **) , = Kernel. , as: nil, using: nil, expected_model: Syskit::Device, class: MasterDeviceInstance , root_task_arguments = Kernel. , MasterDeviceInstance::KNOWN_PARAMETERS # Check for duplicates if ![:as] raise ArgumentError, "no name given, please provide the :as option" end name = [:as] if existing = devices[name] raise ArgumentError, "device '#{name}' is already defined: #{existing}" end # Verify that the provided device model matches what we expect if !(device_model < [:expected_model]) raise ArgumentError, "#{device_model} is not a #{[:expected_model].short_name}" end # If the user gave us an explicit selection, honor it driver_model = begin [:using] || device_model.default_driver rescue Ambiguous => e raise e, "#{e.}, select one explicitely with the using: option of the 'device' statement", e.backtrace end if driver_model.respond_to?(:find_data_service_from_type) driver_model = begin driver_model.find_data_service_from_type(device_model) rescue Syskit::AmbiguousServiceSelection => e raise e, "#{e.}, select one explicitly with the using: option of the 'device' statement", e.backtrace end if !driver_model raise ArgumentError, "#{[:using]}, given as the using: option to create #{self}, is not a driver for #{device_model}" end end driver_model = driver_model.to_instance_requirements device_instance = [:class].new( self, name, device_model, , driver_model, root_task_arguments) invalidate_dependency_injection device_model.apply_device_configuration_extensions(device_instance) device_instance.doc(doc || MetaRuby::DSLs.parse_documentation_block(->(file) { Roby.app.app_file?(file) }, /^device$/)) register_device(name, device_instance) # And register all the slave services there is on the driver driver_model.service.each_slave_data_service do |slave_service| slave_device = SlaveDeviceInstance.new(device_instance, slave_service) device_instance.slaves[slave_service.name] = slave_device register_device("#{name}.#{slave_service.name}", slave_device) end device_instance end |
#each_device(&block) ⇒ Object
199 200 201 |
# File 'lib/syskit/robot/robot_definition.rb', line 199 def each_device(&block) devices.each_value(&block) end |
#each_master_device ⇒ Object
Enumerates all master devices that are available on this robot
204 205 206 207 208 |
# File 'lib/syskit/robot/robot_definition.rb', line 204 def each_master_device return enum_for(__method__) if !block_given? devices.find_all { |name, instance| instance.kind_of?(MasterDeviceInstance) }. each { |_, instance| yield(instance) } end |
#each_slave_device ⇒ Object
Enumerates all slave devices that are available on this robot
211 212 213 214 215 |
# File 'lib/syskit/robot/robot_definition.rb', line 211 def each_slave_device return enum_for(__method__) if !block_given? devices.find_all { |name, instance| instance.kind_of?(SlaveDeviceInstance) }. each { |_, instance| yield(instance) } end |
#empty? ⇒ Boolean
17 18 19 |
# File 'lib/syskit/robot/robot_definition.rb', line 17 def empty? devices.empty? end |
#find_device(name) ⇒ DeviceInstance?
Returns a device by its name
74 75 76 |
# File 'lib/syskit/robot/robot_definition.rb', line 74 def find_device(name) devices[name] end |
#find_through_method_missing(m, args) ⇒ Object
244 245 246 247 |
# File 'lib/syskit/robot/robot_definition.rb', line 244 def find_through_method_missing(m, args) MetaRuby::DSLs.find_through_method_missing( self, m, args, '_dev'.freeze => :find_device) || super end |
#has_device?(name) ⇒ Boolean
Returns true if name
is the name of a device registered on
this robot model
67 68 69 |
# File 'lib/syskit/robot/robot_definition.rb', line 67 def has_device?(name) devices.has_key?(name.to_str) end |
#has_through_method_missing?(m) ⇒ Boolean
239 240 241 242 |
# File 'lib/syskit/robot/robot_definition.rb', line 239 def has_through_method_missing?(m) MetaRuby::DSLs.has_through_method_missing?( self, m, '_dev'.freeze => :has_device?) || super end |
#inject_di_context(requirements) ⇒ Object
Modify the raw requirements to add context information
14 15 |
# File 'lib/syskit/robot/robot_definition.rb', line 14 def inject_di_context(requirements) end |
#invalidate_dependency_injection ⇒ Object
217 218 219 |
# File 'lib/syskit/robot/robot_definition.rb', line 217 def invalidate_dependency_injection @di = nil end |
#register_device(name, device_instance) ⇒ Object
195 196 197 |
# File 'lib/syskit/robot/robot_definition.rb', line 195 def register_device(name, device_instance) devices[name] = device_instance end |
#through(com_bus, &block) ⇒ Object
Makes all devices declared in the provided block are using the given bus
For instance:
through 'can0' do
device 'motors'
end
is equivalent to
device('motors').
attach_to('can0')
92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/syskit/robot/robot_definition.rb', line 92 def through(com_bus, &block) if com_bus.respond_to?(:to_str) bus = find_device(com_bus.to_str) if !bus raise ArgumentError, "communication bus #{com_bus} does not exist" end end if !bus.respond_to?(:through) raise ArgumentError, "#{bus} is not a communication bus" end bus.through(&block) bus end |
#to_dependency_injection ⇒ Object
Returns a dependency injection object that maps names to devices
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/syskit/robot/robot_definition.rb', line 222 def to_dependency_injection if !@di result = DependencyInjection.new device_model_to_instance = Hash.new devices.each_value do |instance| if !device_model_to_instance.delete(instance.device_model) device_model_to_instance[instance.device_model] = instance end end # Register name-to-device mappings result.add(device_model_to_instance) result.resolve @di = result end return @di.dup end |
#use_robot(robot) ⇒ Object
Add the devices defined in the given robot to the ones defined in self.
If robot and self have devices with the same names, the ones in self take precedence
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/syskit/robot/robot_definition.rb', line 31 def use_robot(robot) return [] if robot.empty? if devices.empty? # Optimize the 'self is empty' codepath because it's # actually very common ... and it allows us to reuse the # caller's DI object @di = robot.to_dependency_injection @devices = robot.devices.dup return devices.values end new_devices = [] robot.devices.each do |device_name, device| if !devices.has_key?(device_name) devices[device_name] = device new_devices << device end end if !new_devices.empty? invalidate_dependency_injection end new_devices rescue Exception invalidate_dependency_injection raise end |