# rock/syskit: How to add multiple instances of same component into a network

I've been going through Syskit tutorials at rock-robotics.org. In the tutorials e.g. First composition, there are two different components declared with:

 add Controldev::JoystickTask, :as => "cmd"


I was wondering how could I add an additional RockTutorialControl into the composition, so that the instantiation would then create two separate instances of the same component?

I've tried something like

add RockTutorial::RockTutorialControl, :as => "foo"


but this apparently isn't the way to go. syskit instanciate command shows only one instance of RockTutorialControl, but gives two roles to it (rock and foo). What is the meaning of "role" in this context?

I've noticed that the tutorial explains how to make multiple instances of the same component when we're declaring our components as Devices. But how to do this with components that should not be concerned as devices?

BR, Mathias

EDIT:

This was my first question to StackExchange, and I don't know what's the policy for adding additional information to the original question, but here we go:

It seems that both the deployment and configuration need to be different when there are two instances of the same component. I did a small scale testing with two components:

using_task_library 'foobar_user'

module FooModule
class FooControl < Syskit::Composition

producer_child.connect_to proxy_child
proxy_child.connect_to consumer_child
end
end


where FoobarUser::Task has an input & output port of /std/string. FoobarProxy::Task has corresponding i&o ports. FoobarUser::Task has also two configurations called 'default' and 'other'. It also has two deployments 'foo_depl' and 'bar_depl'.

In order to create a "pipeline" where data flows producer ==> proxy ==> consumer, I made define line:

define 'conf_and_depl', FooModule::FooControl.use('producer' => FoobarUser::Task.use_conf('other').prefer_deployed_tasks(/foo_depl/), 'consumer' => FoobarUser::Task.use_conf('default').prefer_deployed_tasks(/bar_depl/))


and then instanciated the network with

syskit instanciate scripts/03-nwtest.rb conf_and_depl_def!


The component instanciation failed if either use_conf or prefer_deployed_tasks clause was left out. In both cases the produced error was "cannot deploy the following tasks... ...multiple possible deployments, choose one with #prefer_deployed_tasks".

This is what syskit should do, in the end syskit decides about the amount of modules. If you simply add the Requirement a second time syskit recognizes that they can be merged together and removes during instanciation the second one. (to be more precise it merges them together).

You have to add different confiugations and/or build up connections that differ from the usage of the first one.

Hope this clarifies.

Best, Matthias

• Thanks! I edited the original question and it now claims that both, the configuration and the deployment need to be unique. Is this correct, or just wrong interpretation of an inexperienced user? Aug 6 '14 at 21:25

There are basically two types of components in a network from the point of view of syskit, functional components and device drivers.

Functional components behave as pure functions. It means that two components whose inputs are connected to the same source and that have the same configuration should produce the exact same output. Most components are like this, and that's how syskit works: it is able to find out which components are identical and merge them.

Devices are there to provide entry/exit points for the data, i.e. they tell syskit that the component is not functional but pulls, push or both pushes and pulls data from "the outside world". In a robot, these are provided by hardware which is where the name comes from. Note that for instance a random generator would also need to be declared as a device even though there is no real "device" below.

If you want to force syskit to instanciate the same component twice even though they have the same input connections, you therefore have to either make them device drivers and tie them to different devices, or assign different configurations. Note that they can be dummy configurations, i.e.

--- name:default
# Real configuration goes there
--- name:foo
# Empty dummy configuration to force double-instance
--- name:bar
# Empty dummy configuration to force double-instance

define 'foo', Composition.use(Component.use_conf('foo', 'default'))
define 'bar', Composition.use(Component.use_conf('bar', 'default'))


About the deployments: what I have described so far is how two components get merged or not. Another issue is that, once two instances of the same component model end up in the final network, they have to be deployed. Since they are from the same component model, syskit cannot choose for you (see P.S. below for more details). There is actually a tutorial on that later on in the tutorial series you are currently doing.

P.S.: actually syskit could choose for you. The issue then is that you would not be able to easily understand what each component does when you look at rock-display. Indeed, the same component instance (let's say task1) could have different rols in the same network, depending on e.g. the order in which syskit would have assigned the tasks. Looking at a running system in rock-display and/or at logs with rock-replay would be hell. An integration of Syskit and Rock live display / log tools would solve that nicely, but we're not there yet.