class Syskit::Robot::RobotDefinition

RobotDefinition objects describe a robot through the devices that are available on it.

Attributes

devices[R]

The devices that are available on this robot

Public Class Methods

new() click to toggle source
# File lib/syskit/robot/robot_definition.rb, line 6
def initialize
    @devices = Hash.new
end

Public Instance Methods

clear() click to toggle source
# File lib/syskit/robot/robot_definition.rb, line 21
def clear
    invalidate_dependency_injection
    devices.clear
end
com_bus(type, options = Hash.new) click to toggle source

Declares a new communication bus

# File lib/syskit/robot/robot_definition.rb, line 61
def com_bus(type, options = Hash.new)
    device(type, options.merge(expected_model: Syskit::ComBus, class: ComBus))
end
device(device_model, doc: nil, **options) click to toggle source

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

# File lib/syskit/robot/robot_definition.rb, line 135
def device(device_model, doc: nil, **options)
    options, device_options = Kernel.filter_options options,
        as: nil,
        using: nil,
        expected_model: Syskit::Device,
        class: MasterDeviceInstance
    device_options, root_task_arguments = Kernel.filter_options device_options,
        MasterDeviceInstance::KNOWN_PARAMETERS

    # Check for duplicates
    if !options[:as]
        raise ArgumentError, "no name given, please provide the :as option"
    end
    name = options[: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 < options[:expected_model])
        raise ArgumentError, "#{device_model} is not a #{options[:expected_model].short_name}"
    end

    # If the user gave us an explicit selection, honor it
    driver_model =
        begin options[:using] || device_model.default_driver
        rescue Ambiguous => e
            raise e, "#{e.message}, 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.message}, select one explicitly with the using: option of the 'device' statement", e.backtrace
            end
        if !driver_model
            raise ArgumentError, "#{options[: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 = options[:class].new(
        self, name, device_model, device_options,
        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) click to toggle source
# File lib/syskit/robot/robot_definition.rb, line 199
def each_device(&block)
    devices.each_value(&block)
end
each_master_device() { |instance| ... } click to toggle source

Enumerates all master devices that are available on this robot

# 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() { |instance| ... } click to toggle source

Enumerates all slave devices that are available on this robot

# 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?() click to toggle source
# File lib/syskit/robot/robot_definition.rb, line 17
def empty?
    devices.empty?
end
find_device(name) click to toggle source

Returns a device by its name

@return [DeviceInstance,nil]

# File lib/syskit/robot/robot_definition.rb, line 74
def find_device(name)
    devices[name]
end
find_through_method_missing(m, args) click to toggle source
# 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) click to toggle source

Returns true if name is the name of a device registered on this robot model

# 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) click to toggle source
# 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) click to toggle source

Modify the raw requirements to add context information

# File lib/syskit/robot/robot_definition.rb, line 14
def inject_di_context(requirements)
end
invalidate_dependency_injection() click to toggle source
# File lib/syskit/robot/robot_definition.rb, line 217
def invalidate_dependency_injection
    @di = nil
end
register_device(name, device_instance) click to toggle source
# File lib/syskit/robot/robot_definition.rb, line 195
def register_device(name, device_instance)
    devices[name] = device_instance
end
through(com_bus, &block) click to toggle source

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')
# 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() click to toggle source

Returns a dependency injection object that maps names to devices

# 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) click to toggle source

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

# 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