diff --git a/source/syskit_basics/composition.html.md b/source/syskit_basics/composition.html.md
index 6cde23b..25bdd1e 100644
--- a/source/syskit_basics/composition.html.md
+++ b/source/syskit_basics/composition.html.md
@@ -107,7 +107,7 @@ $ syskit gen cmp arm_cartesian_control_wdls
-#### OroGen packages in Syskit
+#### OroGen packages in Syskit {#orogen}
As described in our [brief introduction](index.html), oroGen packages are
@@ -178,14 +178,14 @@ file as follows (`-rgazebo` is necessary because we are importing models from
-We may now start adding connections in the composition definition. The following
-code snippets will only reproduce the composition definition itself, omitting
-what is around it. The `as` arguments when adding composition elements create an
-accessor for the children. The children ports are then accessible with a `_port`
-accessor. For instance, the `ctrl_out` port of the `CartCtrl` component is
-accessed with `position2twist_child.ctrl_out_port`.
+We may now start adding connections in the composition definition. The `as`
+arguments when adding composition elements create an accessor for the children.
+The children ports are then accessible with a `_port` accessor. For instance,
+the `ctrl_out` port of the `CartCtrl` component is accessed with
+`position2twist_child.ctrl_out_port`.
-Let's connect that one to the `WDLSSolver` twist input, and the WDLSSolver command to the actual arm command input:
+Let's connect that one to the `WDLSSolver` twist input, and the WDLSSolver
+command to the actual arm command input:
~~~ruby
class ArmCartesianControlWdls < Syskit::Composition
@@ -212,13 +212,13 @@ arm_child.joints_status_port.
~~~
However, the cartesian position feedback is not directly provided by the Gazebo
-model. Fortunately, the `control/orogen/robot_frames` component does the
-joint-to-cartesian conversion.
+model. Fortunately, the `control/orogen/robot_frames` project provides components
+to do the joint-to-cartesian conversion.
Let's add it to our workspace [in the same way we added
`control/orogen/cart_ctrl_wdls`](#add_package), import it in the composition
-file with `using_task_library` and finally add it to the composition. You must
-restart the IDE after this.
+file with `using_task_library` and reload the models in the IDE.
+Then, finally add it to the composition.
~~~ruby
# This is in bundles/common_models
@@ -233,16 +233,18 @@ module SyskitBasics
add OroGen::CartCtrlWdls::WDLSSolver, as: 'twist2joint_velocity'
add OroGen::CartCtrlWdls::CartCtrl, as: 'position2twist'
add CommonModels::Devices::Gazebo::Model, as: 'arm'
- add OroGen::RobotFrames::SingleChainProducer, as: 'joint2pose'
+ add OroGen::RobotFrames::SingleChainPublisher, as: 'joint2pose'
position2twist_child.ctrl_out_port.
connect_to twist2joint_velocity_child.desired_twist_port
twist2joint_velocity_child.solver_output_port.
connect_to arm_child.joints_cmd_port
arm_child.joints_status_port.
- connect_to joint2pose_child.joints_samples_port
+ connect_to twist2joint_velocity_child.joint_status_port
+ arm_child.joints_status_port.
+ connect_to joint2pose_child.joints_samples_port
joint2pose_child.tip_pose_port.
- connect_to position2twist_child.cartesian_status_port
+ connect_to position2twist_child.cartesian_status_port
end
end
end
@@ -259,7 +261,7 @@ by **exporting** the command port on the composition interface. This is done
with the `export` keyword, in the composition class context:
~~~ruby
-export position2twist.command_child
+export position2twist_child.command_port
~~~
In the IDE, this is represented as a port on the composition, and a connection
diff --git a/source/syskit_basics/constant_generator.html.md b/source/syskit_basics/constant_generator.html.md
index 136533d..68f71fc 100644
--- a/source/syskit_basics/constant_generator.html.md
+++ b/source/syskit_basics/constant_generator.html.md
@@ -10,8 +10,8 @@ sort_info: 30
generator. The first generator one usually creates is a constant one, creating an
interface to send a constant command from Syskit into a control network.
-We will create the command generator on this page, and then [deploy and run
-it](deployment.html).
+We will create the command generator now, then bind the result [to the simulation](devices.html)
+and finally [deploy and run it](deployment.html).
We will also learn how to write unit tests.
@@ -21,14 +21,15 @@ For the command, let's generate a single constant command. It will allow us to
move the arm tip from one point to another, expressed in the cartesian frame.
`bundles/common_models` provides `Compositions::ConstantGenerator`, a generic
-component that produces a constant command of a certain type. This generator is
+implementation of a component that periodically emits a value of a certain type. This generator is
a `Syskit::RubyTaskContext`, which is like an oroGen component that is part of
the Syskit process. It's useful to create very simple components without having
-to get through the whole oroGen step, or stub existing components.
+to get through the whole oroGen step. It is also used in tests to stub existing components.
-`ConstantGenerator` is generic, so it's rarely used as-is. We will instead
-create a `Compositions::ArmCartesianConstantCommandGenerator` generator specialized
-for our purposes.
+`ConstantGenerator` is generic, so it's not used as-is. One instead
+creates a specific component for the task at hand. In our case, we'll create
+the `Compositions::ArmCartesianConstantCommandGenerator` generator specialized for
+our purposes.
First, generate the new model
@@ -71,8 +72,7 @@ page.
## Improving the arguments
The format of the 'values' is actually awkward for a command generator. Let's
-provide better arguments. We need to update `#values` when position or
-orientation are set.
+provide a better `setpoint` argument that is transformed to set `values`.
~~~ruby
class ArmCartesianConstantCommandGenerator < ...
@@ -122,9 +122,8 @@ its correctness.
Each time we ran `syskit gen`, files were created both in `models/` and
`test/`. The default Syskit test framework is the spec implementation of
-[minitest](https://github.com/seattlerb/minitest)
-
-Let's now write the tests for our generator.
+[minitest](https://github.com/seattlerb/minitest). Let's now adapt these
+templates for our generator.
Start by deleting the boilerplate test from `test/compositions/test_arm_cartesian_constant_command_generator.rb`.
@@ -240,8 +239,8 @@ end
## Creating the ArmCartesianConstantControlWdls Composition
-Whenever a control loop is created, it is common to also create both the corresponding
-constant generator (if it does not exist) and the corresponding composition.
+Now that we have a generator, let's bind it to our control loop to have
+something that can move and hold our arm to a given pose.
We'll create the composition now.
@@ -414,7 +413,7 @@ module SyskitBasics
Types.base.commands.Joints.new(
time: Time.at(0),
names: joint_names,
- values: joint_commands)]
+ elements joint_commands)]
end
def values
diff --git a/source/syskit_basics/deployment.html.md b/source/syskit_basics/deployment.html.md
index 74829ee..2d3ea0a 100644
--- a/source/syskit_basics/deployment.html.md
+++ b/source/syskit_basics/deployment.html.md
@@ -31,11 +31,13 @@ All oroGen components have a default deployment scheme of one component per
process. The triggering mechanism does not have a default, but the
`port_driven` scheme (where the component is triggered whenever data is
received on its inputs) is a very common scheme. If you look into the
-`cart_ctrl_wdls` package, you would see that
+`cart_ctrl_wdls` package, you would see that it's what the package's components
+use.
One usually starts with the defaults defined in the oroGen file. We therefore
only have left to give a name to the components Syskit is using. This is done
in the robot's config file with:
+{: #requires}
~~~ruby
Robot.requires do
@@ -53,7 +55,8 @@ end
Now that we've required our toplevel profile in the robot configuration file,
we can inspect our app using the IDE by simply providing the `-rgazebo` flag.
Only new files, not yet required by the config file, must be specified on the
-command line. {: .callout .callout-info}
+command line.
+{: .callout .callout-info}
## Component configuration {#configuration}
@@ -88,7 +91,7 @@ $ syskit gen orogenconf cart_ctrl_wdls::WDLSSolver
$ syskit gen orogenconf cart_ctrl_wdls::CartCtrl
exists config/orogen/
create config/orogen/cart_ctrl_wdls::CartCtrl.yml
-$ syskit gen orogenconf robot_frames::SingleChainProducer
+$ syskit gen orogenconf robot_frames::SingleChainPublisher
exists config/orogen/
create config/orogen/robot_frames::SingleChainPublisher.yml
~~~
@@ -98,7 +101,7 @@ Let's look at them one by one, to see what needs to actually be configured.
- `cart_ctrl_wdls::WDLSSolver`. There are robot model parameters as well as tip
and root. The former should be extracted from the SDF configuration, but the
- tip and root can be set. The only algorithm parameter that does not seem to
+ tip and root have to be set. The only algorithm parameter that does not seem to
have a sane default is the `lambda` parameter. The documentation mentions 0.1
has a known-good parameter for some arm, let's pick that and keep in mind
that it might be wrong.
@@ -107,13 +110,18 @@ Let's look at them one by one, to see what needs to actually be configured.
represent a twist, which means that we only need to update the velocity
and angular velocity fields. Let's set `0.1` in linear and `2.deg` in angular
(the `.deg` suffix will convert a degree value in radians).
-- `robot_frames::SingleChainPublisher` only has robot model and tip/root parameters.
+- `robot_frames::SingleChainPublisher` only has robot model that we will
+ extract from the SDF model, and the tip/root parameters that have to be set
+
+**Note** in order to ensure consistency between the tip and root parameters of
+`SingleChainPublisher` and `WDLSSolver`, another way to handle this is to make
+them parameters of the compositions.
+{: .callout .callout-info}
The root and tip in our case are the base and hand of the robot. The link names are prefixed
-with the model name (here, `ur10`) so `root` should
+with the model name (here, `ur10_fixed`) so `root` should
be `ur10_fixed::ur10::base` and `tip` should be `ur10_fixed::ur10::wrist_3`. One can find this out by looking at
-the SDF file - which is downloaded by Gazebo in
-`$HOME/.gazebo/models/ur10/ur10.sdf`. Alternatively, the chain can be
+the SDF file. Alternatively, the chain can be
inspected using the `rock-transformer` tool:
@@ -204,9 +212,10 @@ define 'arm_cartesian_constant_control',
We now need to modify the oroGen component models to use the robot argument.
Since oroGen components are auto-generated by Syskit, there's a special
mechanism to allow modifying the generated classes after the fact. When Syskit
-loads an oroGen, and after it has created the task classes, it will attempt to
+loads an oroGen package, and after it has created the task classes, it will attempt to
load a file named like the project in `models/orogen/`. In the case of the
`robot_frames` project, this would be `models/orogen/robot_frames.rb`.
+{: #orogen_extension_files}
In the IDE, when displaying a task model under the `OroGen` namespace, a project
that has no associated extension file in `models/orogen/` has the following message:
@@ -244,7 +253,7 @@ class OroGen::CartCtrlWdls::WDLSSolver
def configure
super # call super as described in the template
- properties.robot_model = robot.sdf_model.make_root.to_s
+ properties.robot_model = robot.sdf_model.make_root.to_xml_string
properties.robot_model_format = :ROBOT_MODEL_SDF
end
end
@@ -258,7 +267,7 @@ class OroGen::RobotFrames::SingleChainPublisher
def configure
super # call super as described in the template
- properties.robot_model = robot.sdf_model.make_root.to_s
+ properties.robot_model = robot.sdf_model.make_root.to_xml_string
properties.robot_model_format = :ROBOT_MODEL_SDF
end
end
@@ -279,19 +288,23 @@ argument :robot
# @param [String] property_name the name of the property being
# verified
# @raise [ArgumentError] if the link is not in the model
-def verify_link_in_model(link_name)
- if !robot.sdf_model.each_link.any? { |link| link.name == link_name }
- raise ArgumentError, "link name '#{link_name}' is not a link of the robot model. Available links: #{robot.sdf_model.each_link.map(&:name).sort.join(", ")}"
+def verify_link_in_model(model, link_name)
+ if !model.each_link.any? { |link| link.full_name == link_name }
+ raise ArgumentError, "link name '#{link_name}' is not a link of the robot model. Existing links: #{model.each_link.map(&:full_name).sort.join(", ")}"
end
end
def configure
super
- verify_link_in_model(properties.root)
- verify_link_in_model(properties.tip)
+ # Extract the model into its own SDF document
+ as_root = robot.sdf_model.make_root
+ # And get the new model
+ model = as_root.each_model.first
+ verify_link_in_model(model, properties.root)
+ verify_link_in_model(model, properties.tip)
- properties.robot_model = robot.sdf_model.make_root.to_s
+ properties.robot_model = as_root.to_xml_string
properties.robot_model_format = :ROBOT_MODEL_SDF
end
~~~
@@ -344,13 +357,20 @@ describe WDLSSolver do
EOSDF
- @profile = flexmock(sdf_model: SDF::Element.from_xml_string(xml))
+ # We don't really need a full profile object, only an object
+ # that provides a Model object from a '#sdf_model' attribute
+ #
+ # Let's fake one using flexmock. Flexmock is loaded as part
+ # Of Syskit's test harness
+ #
+ # https://github.com/doudou/flexmock
+ @profile = flexmock(sdf_model: SDF::Model.from_xml_string(xml))
end
it "sets the robot model from its 'robot' argument" do
# Create a fake test configuration with valid root and tip
syskit_stub_conf WDLSSolver, 'default',
- data: { 'root' => 'root_test', 'tip' => 'tip_test' }
+ data: { 'root' => 'test::root_test', 'tip' => 'test::tip_test' }
task = syskit_stub_deploy_and_configure(
WDLSSolver.with_arguments(robot: profile))
assert_equal "#{profile.sdf_model.to_xml_string}",
@@ -359,23 +379,23 @@ describe WDLSSolver do
it "raises if the root link does not exist" do
syskit_stub_conf WDLSSolver, 'default',
- data: { 'root' => 'invalid', 'tip' => 'tip_test' }
+ data: { 'root' => 'invalid', 'tip' => 'test::tip_test' }
e = assert_raises(ArgumentError) do
syskit_stub_deploy_and_configure(
WDLSSolver.with_arguments(robot: profile))
end
- assert_equal "link name 'invalid' is not a link of the robot model. Existing links: root_test, tip_test",
+ assert_equal "link name 'invalid' is not a link of the robot model. Existing links: test::root_test, test::tip_test",
e.message
end
it "raises if the tip link does not exist" do
syskit_stub_conf WDLSSolver, 'default',
- data: { 'root' => 'root_test', 'tip' => 'invalid' }
+ data: { 'root' => 'test::root_test', 'tip' => 'invalid' }
e = assert_raises(ArgumentError) do
syskit_stub_deploy_and_configure(
WDLSSolver.with_arguments(robot: profile))
end
- assert_equal "link name 'invalid' is not a link of the robot model. Existing links: root_test, tip_test",
+ assert_equal "link name 'invalid' is not a link of the robot model. Existing links: test::root_test, test::tip_test",
e.message
end
end
@@ -432,6 +452,7 @@ file. Syskit profiles are added in the action interface there, so that their
definitions are exported as an action with a `_def` suffix.
Let's modify the `actions` block in `config/robots/gazebo.rb` to have:
+{: #main}
~~~ruby
Robot.actions do
@@ -440,8 +461,12 @@ Robot.actions do
end
~~~
+**Note**: the profile is available in the actions block because [we've required it in the requires block](#requires)
+{: .callout .callout-info}
+
After modifying the config file, the IDE needs to be quit and started again. We
-can then look at the `Main` interface and see that it indeed has a `arm_cartesian_constant_control_def` action:
+can then look at the `Main` interface and see that it indeed has `_dev` actions for
+the devices in `Base`, and `_def` actions for the definitions in `ArmControl`.

@@ -456,13 +481,12 @@ rock-gazebo empty_world
~~~
Once started, the simulation can stay running regardless of whether the Syskit
-app itself gets restarted. You can then start the app either on the command
-line with
+app itself gets restarted. You can then start the app using the IDE, and
+send the command through the Syskit shell. The following video show you the process. Its goal
+is to give you a feeling for Syskit's runtime workflow. Detailed explanations will come later [in the runtime part of this documentation](../syskit_runtime/index.html)
-~~~
-syskit run -rgazebo
-~~~
-
-Or, if you prefer, in the IDE as in the following video. Start then the action within the IDE.
+
+
+
-TODO: video
+Before we move on to the Syskit runtime aspects, [let's recap what we've just seen](recap.html){:.btn .btn-primary}
diff --git a/source/syskit_basics/devices.html.md b/source/syskit_basics/devices.html.md
index c8fb9b3..df4b0e5 100644
--- a/source/syskit_basics/devices.html.md
+++ b/source/syskit_basics/devices.html.md
@@ -27,7 +27,7 @@ streams of data - one cannot duplicate devices. They are bound to hardware,
and we still don't know how to grow new devices on the robot on-demand.
This difference also exists in the Syskit system. The robot interface, the
-devices, are described separately. We will just see how this is done, and
+devices, are described separately. We will now see how this is done, and
how we can use these devices within our arm control network, binding the
simulated arm with the control network.
@@ -64,7 +64,7 @@ module SyskitBasics
module Profiles
module Gazebo
profile 'Base' do
- use_gazebo_model 'model://ur10/ur10.sdf'
+ use_gazebo_model 'model://ur10_fixed/model.sdf'
use_sdf_world
end
end
@@ -72,7 +72,7 @@ module SyskitBasics
end
~~~
-And have a look at the generated devices:
+And have a look at the generated devices with `syskit ide -rgazebo models/profiles/gazebo/base.rb`:

@@ -97,6 +97,12 @@ definition. Then, `define` the cartesian and joint position controls _for our
UR10 robot in gazebo_ by injecting the UR10 device as the 'arm' child of the
composition.
+The model name given to `define` in a profile is made out of a [demeter
+chain](https://martinfowler.com/bliki/FluentInterface.html). In Ruby, one can
+easily break the chain with a newline after each method call. Don't forget the
+dots !
+{: .callout .callout-warning}
+
~~~ruby
require 'models/profiles/gazebo/base'
require 'models/compositions/arm_cartesian_constant_control_wdls'
diff --git a/source/syskit_basics/getting_started.html.md b/source/syskit_basics/getting_started.html.md
index fbdeb22..06c686a 100644
--- a/source/syskit_basics/getting_started.html.md
+++ b/source/syskit_basics/getting_started.html.md
@@ -14,11 +14,9 @@ allow us to continue with actually doing something with the system.
In Rock, the central place where the system design and integration happens is a
_bundle_. A bundle package is created in the `bundles/` folder of your Rock
-workspace.
-
-For all intents and purposes, so far, bundles are a collection of Syskit models
-(in `models/`), configuration files (in `config/`) and SDF scene (`scenes/`)
-and model descriptions (`models/sdf/`).
+workspace. For the time being, you can see bundles as a collection of
+Syskit models (in `models/`), configuration files (in `config/`), SDF scenes
+(`scenes/`) and SDF models (`models/sdf/`).
The following assumes that you have a [bootstrapped Rock
installation](../workspace/index.html), and that you have a terminal in which this
@@ -66,14 +64,11 @@ default[INFO]: closed communication
The [Scene Description Format](http://sdformat.org) is a XML format defined by the
Gazebo developers to describe both scenes and objects in these scenes (as e.g.
-robots).
-
-What we're going to learn along this documentation is to leverage the
-information present in an SDF file as possible, with the goal of having the SDF
-be the authoritative information source for any information that can be
-represented in it.
+robots). We're going to learn how to leverage the information present in an SDF
+file as possible, with the goal of having the SDF be the authoritative
+information source for any information that can be represented in it.
-But for now, let's get to create ourselves a scene with a robot in it. This
+But for now, let's get to create ourselves a scene with a robot in it. We
will **not** describe the SDF format in details, there's a lot of
Gazebo-related documentation about that, [including a reference of the format
on sdformat.org](http://sdformat.org/spec)
@@ -85,10 +80,9 @@ your robot should at least be described in a separate model to allow you to
reuse it in different simulation scenes.
For the purpose of this part of the documentation, we'll use Gazebo's UR10 arm
-model as our robot. We however need to integrate it in another model so that its
-base is fixed (using [this method](http://answers.gazebosim.org/question/5065/how-to-attach-arm-to-a-static-base-using-sdf/))
-
-Let's create a new model. The models are saved in `models/sdf/`, let's create
+model as our robot. We however need to integrate it in another model so that
+its base is fixed (using [this
+method](http://answers.gazebosim.org/question/5065/how-to-attach-arm-to-a-static-base-using-sdf/)) Models are saved in `models/sdf/`, let's create
`models/sdf/ur10_fixed` and create a Gazebo model description file `models/sdf/ur10_fixed/model.config` with
~~~xml
@@ -96,7 +90,7 @@ Let's create a new model. The models are saved in `models/sdf/`, let's create
Universal Robotics UR10 robot arm on a fixed base
- 1.0.2
+ 1.0model.sdf
~~~
@@ -185,7 +179,13 @@ newly-created `config/robots/gazebo.rb` configuration file to add:
~~~ruby
Robot.init do
- # IMPORTANT: do not delete the code from the generated template
+ ## You can load plugins here
+ # Roby.app.using 'fault_injection'
+ # Roby.app.using 'syskit'
+
+ ## Change the scheduler
+ require 'roby/schedulers/temporal'
+ Roby.scheduler = Roby::Schedulers::Temporal.new
# The rock-gazebo bridge requires models from the 'common_models' bundle.
# It already depends on it, but we need to manually add the bundle to the
diff --git a/source/syskit_basics/media/devices.png b/source/syskit_basics/media/devices.png
index 89f6569..85aa17f 100644
Binary files a/source/syskit_basics/media/devices.png and b/source/syskit_basics/media/devices.png differ
diff --git a/source/syskit_basics/media/initial_rock_gazebo_viz.jpg b/source/syskit_basics/media/initial_rock_gazebo_viz.jpg
index 5c7f6eb..b514a95 100644
Binary files a/source/syskit_basics/media/initial_rock_gazebo_viz.jpg and b/source/syskit_basics/media/initial_rock_gazebo_viz.jpg differ
diff --git a/source/syskit_basics/media/main_action_with_arm_control_def.png b/source/syskit_basics/media/main_action_with_arm_control_def.png
index 482e42a..3f05c64 100644
Binary files a/source/syskit_basics/media/main_action_with_arm_control_def.png and b/source/syskit_basics/media/main_action_with_arm_control_def.png differ
diff --git a/source/syskit_basics/recap.html.md b/source/syskit_basics/recap.html.md
new file mode 100644
index 0000000..e37fb9c
--- /dev/null
+++ b/source/syskit_basics/recap.html.md
@@ -0,0 +1,224 @@
+---
+layout: documentation
+title: Recap
+sort_info: 60
+---
+
+# Recap
+
+Let's recap what we've seen in this Basics section.
+
+### Workspace
+
+Autoproj is Rock's tool to manage (install and update) packages. "Packages" are the unit
+of integration of the Rock software. The role of a workspace build
+configuration is to ensure repeatability in the installation of a system's
+software
+
+- [the initial bootstrap](../workspace/index.html) installs a predefined set of
+ packages as defined by a given build configuration
+- packages are also [added during development](composition.html#add_package),
+ when the functionality is required
+
+### Bundles
+
+[Bundles](getting_started.html) are the package within which we create Syskit models and code. It is the _place of integration_.
+
+From Syskit's point of view, a bundle has a toplevel namespace under which the rest of the app is defined. It is by default the CamelCased version of the bundle's folder name (`syskit_basics` becomes `SyskitBasics`).
+
+A given bundle may contain multiple Syskit app configurations. The entry point
+for each configuration is a file in `config/orogen/`. One usually creates one
+bundle per class of system, and creates at least one configuration for
+simulation and one for the live system. Syskit tools take a `-rROBOT_NAME`
+argument to specify which configuration should be loaded.
+
+It is possible to reuse models from another bundle by updating `Roby.app.search_path`
+either globally in `config/init.rb` or per-robot in the `Robot.init` block of the robot
+configuration file.
+
+Within bundles:
+
+- separate SDF models are saved within `models/sdf/`
+- SDF scenes are saved within `scenes/#{scene_name}/#{scene_name}.world`
+- [compositions](#compositions) are in `models/compositions/`
+- [ruby tasks](#ruby_tasks) are in `models/compositions/`
+- [orogen extension files](#orogen) are in `models/orogen/`
+- [profiles](#profiles) are in `models/profiles/`
+- [orogen configuration files](#orogen_config) are in `config/orogen/`.
+ Configuration-specific files (e.g. in `config/orogen/gazebo/`) take precedence.
+- within the Syskit model folders (`compositions/` and `profiles/`), the convention
+ is to have subfolders for models that are specific to a given robot configuration
+ (e.g. `profiles/gazebo/` for models that are specific to the `gazebo` configuration).
+ The generators enforce this when given the `-rROBOT_NAME` option.
+- the folder structure in `models/` maps one-to-one to the folder structure in `test/`
+
+### Components and Compositions {#compositions}
+
+Components are the basic construction block in a Syskit system.
+[Compositions](composition.html) are used to turn single components into
+more complex functional units, by binding the components together.
+
+- a composition template is created using
+
+ ~~~
+ syskit gen NameOfComposition
+ ~~~
+- an element within a composition is declared with `add`, a component model
+ (which can be another composition) and a name:
+
+ ~~~ruby
+ class MyComposition < Syskit::Composition
+ add AnotherComponentModel, as: 'generator'
+ end
+ ~~~
+- within the composition model, a composition child is accessed using the
+ child's name and the `_child` suffix. Ports are accessed with the port name and
+ the `_port` suffix. This is how connections are made:
+
+ ~~~ruby
+ source_child.out_port.connect_to sink_child.in_port
+ ~~~
+- a composition can have ports, which are exports of its children ports. This works
+ for both input and output ports. The exported port name is the same as the child's
+ port name, but this can be overriden
+
+ ~~~ruby
+ export source_child.out_port
+ export another_source_child.out_port, as: 'another'
+ ~~~
+
+### oroGen components {#orogen}
+
+oroGen is Rock's way to package C++ functionality into ready-to-use components with
+a standardized interface. These components are imported in Syskit's with
+
+~~~ruby
+using_task_library "name_of_orogen_project"
+~~~
+
+The other role of oroGen is to define types whose instances can be transferred
+between components. If one only wants to use a type defined by an oroGen
+project, but without using the associated components, one does
+
+~~~ruby
+import_types_from "name_of_orogen_project"
+~~~
+
+The corresponding types are accessible under the `Types` object, e.g.
+
+~~~ruby
+Types.base.samples.RigidBodyState
+~~~
+
+On import, Syskit builds a component model that represents the oroGen
+component. This model is accessible [within the `OroGen`
+namespace](composition.html#orogen). It can also be extended to reflect needs
+in the Syskit app, for instance configuration, using [extension
+files](deployment.html#orogen_extension_files).
+
+oroGen components provide a configuration interface as a set of properties.
+These properties are filled using YAML configuration files stored in
+`config/orogen/`, and may also be written in the `configure` method of the
+component's class, in the extension file.
+{: #orogen_config}
+
+### Ruby Tasks {#ruby_tasks}
+
+In a system, one often needs to do some small tasks that are either too small
+to warrant a full-fledged C++ component, or are so tied with the system integration
+that having a C++/Ruby boundary makes understanding hard. For these, Syskit
+allows to implement tasks in Ruby that are integrated within the Syskit
+execution but provide input and output ports to integrate with the rest of the
+components.
+
+Because of the single-threaded nature of Syskit's execution engine, one must
+**not** use ruby tasks to perform a lot of work. This would freeze Syskit.
+Stick to simple tasks, and implement oroGen components for more complex ones.
+{: .callout .callout-warning}
+
+A canonical example for such a task is [the `common_models` bundle's `ConstantGenerator`](constant_generator.html).
+
+Whenever runtime code is present in tasks, as it often is in ruby tasks,
+**write tests**.
+{: .callout .callout-warning}
+
+### Profiles
+
+Profiles are the models that contain functional networks. It is common to have
+compositions made of _abstract_ models, that is components that are not really
+components - such as [device models](devices.html). These abstract components
+can be replaced by actual components within the profiles with the `use` call.
+Moreover, profiles allow to specify arguments to compositions in the process
+of definition.
+
+The model name given to `define` in a profile is made out of a [demeter
+chain](https://martinfowler.com/bliki/FluentInterface.html). In Ruby, one can
+easily break the chain with a newline after each method call. Don't forget the
+dots !
+{: .callout .callout-warning}
+
+- arguments are set with `with_arguments`
+
+ ~~~ruby
+ CompositionModel.with_arguments(arg_name: arg_value)
+ ~~~
+
+- `CompositionModel.use('child_name' => model)` replaces `CompositionModel`'s
+ `child_name` child with the given model. `model` can itself be refined by `use`
+ and `with_arguments`.
+- `CompositionModel.use(model)` replaces any `CompositionModel`
+ child whose model is compatible with `model` by `model`.
+- a definition or device can itself be used as `model` or `CompositionModel` in
+ all these calls, possibly from another profile:
+
+ ~~~ruby
+ define 'first', CompositionModel.use(first_test_dev)
+ define 'second', first_dev.use(AnotherProfile.second_test_dev)
+ define 'third', AnotherProfile.first_dev.use(second_test_dev)
+ ~~~
+
+### Configuration
+
+Apart from the [orogen configuration files](#orogen_config), components can have arguments.
+The choice between a configuration file or a component argument is a matter of system design,
+but there are some guidelines.
+
+**Use task arguments when**
+
+- consistency between different components is necessary, as for instance the robot model
+- a value is to be provided at runtime, as for instance a target pose
+
+**Use configuration files when**
+
+- the values are static (set once and seldom changed)
+
+Arguments can be forwarded from a composition to its children using the following pattern:
+
+~~~ruby
+class C < Syskit::Composition
+ argument :robot
+ add(ChildModel, as: 'generator').
+ with_arguments(robot: from(:parent_task).robot)
+end
+~~~
+
+### Deployments, Actions
+
+Before they are used, components need to be deployed, that is associated with a
+process and a name. This is done in the `requires` block of the robot
+configuration file with
+
+~~~ruby
+Syskit.conf.use_deployment ComponentModel => 'component_name'
+~~~
+
+Actions are the basic block of interaction between a Syskit app and the outside
+world. Moreover, the Main action interface, defined by the `actions` block in
+the robot configuration file is the interface that is being exposed through the
+standard channels (IDE, shell).
+
+Definitions from a profile [are exported on the Main interface](deployment.html#main).
+
+### Runtime
+
+We've only had a glimpse on the Syskit runtime workflow. [Let's dig deeper](../syskit_runtime/index.html){: .btn .btn-primary}
diff --git a/source/workspace/day_to_day.html.erb b/source/workspace/day_to_day.html.md
similarity index 100%
rename from source/workspace/day_to_day.html.erb
rename to source/workspace/day_to_day.html.md