[OCL] Component guidelines

In response to Klaas' mail, I'd like to set the standard for acceptable OCL
C++ components.

There are clearly two groups of components: hardware independent and hardware
dependent components. I believe both groups should be represented in OCL.

The question raises what, for example, a 'demotool' hardware component is of
use to the rest of the world. This and other components control custom
hardware and could only serve as an example. However, examples should be
clear, not confusing and testable on any platform. That just excludes about
any hardware component we have in OCL. Most hardware components were written
at PMA. Maybe they can propose what to do ?

Anyway, *every* component should at least meet these standards before
inclusion in OCL. I'm sure not everything is clear here, help me improve this
text...

1. The component can be loaded by the 'DeploymentComponent' (deployer).
This means each component has a constructor of the form:
Component(const std::string name) : TaskContext(name),...

2. A component that needs a configure() before it can work _must_ be started
in the PreOperational state:
Component(const std::string name) : TaskContext(name, PreOperational),...

3. If a component has properties, they may be read in the configureHook()
function from a file or other source. When reading from a file, the default
file to look for is 'componentname.cpf'. A component attribute may set the
filename to a user defined value. If no such file is present, and the
component requires configuration, configureHook() should fail by returning
false. For example:
bool configureHook() {
if ( this->marshalling()->readProperties( this->getName() + ".cpf" ) == false)
return false;
return true;
}

4. If a component has properties, they may be written in the cleanupHook() to
a file or other destination. The default filename is 'componentname.cpf'. A
component attribute may set the filename to a user defined value. For
example:
void cleanupHook() {
this->marshalling()->writeProperties( this->getName() + ".cpf" )
}

5. if a component has properties and these properties should not be changed by
the user at component runtime, the component must use internal copies of the
property values. The copies are made at startHook(). This allows the
scenario: read properties from file during configure(), tweak one property,
start() using the latest values of the properties. stop() again, tweak
another property, start() again. etc. For example:
bool startHook() {
this->mgain = this->gainProp.get(); // only use 'mgain' for calculations
return true;
}

6. Properties, ports, methods, commands and events are using the online
documentation infrastructure. For example:
this->methods()->addMethod( RTT::method("loadLibrary", &DeploymentComponent::loadLibrary, this),
"Load a new library into memory.",
"Name", "The name of the to be loaded library.");
The RTT allows ports to be not documented, which is only for backwards
compatibility (RTT 1.0). Please do not use this feature, but use:
ports()->addPort(_driveValue[i], "Set the drive reference velocity in rad/s");

7. The component and its member functions are documented using non-trivial
Doxygen comments. Please don't write
/** Constructor */
as a comment. Do write
/** Creates an unconfigured Component. Set the 'ImportantProp' property to a
valid value and use configure() to inform the component of the new value.
*/

8. If possible, document the 'scripting' interface of the component using
@name grouping comments. For example:
(see
)
/**
* @name Script Program Commands
* @{
*/
/**
* Start a Program.
* @param name The name of the Program.
*/
bool startProgram(const std::string& name);

/**
* Stops the execution of a program.
* @param name The name of the Program.
*/
bool stopProgram(const std::string& name);
/** @} */

9. You must provide a separate document describing a usage scenario of the
component with at least one figure. This may be done in a component.dox
(Doxygen style) file or in an component.xml (DocBook) file. The file must be
included during the 'make doc' pass. For example:

10.

Peter

Ruben Smits's picture

[OCL] Component guidelines

On Thursday January 10 2008 15:41:36 Peter Soetens wrote:
> In response to Klaas' mail, I'd like to set the standard for acceptable OCL
> C++ components.
>
> There are clearly two groups of components: hardware independent and
> hardware dependent components. I believe both groups should be represented
> in OCL.
>
> The question raises what, for example, a 'demotool' hardware component is
> of use to the rest of the world. This and other components control custom
> hardware and could only serve as an example. However, examples should be
> clear, not confusing and testable on any platform. That just excludes about
> any hardware component we have in OCL. Most hardware components were
> written at PMA. Maybe they can propose what to do ?

I think it is a good idea to keep OCL clean for other users,
components which are too hardware specific should not be in OCL,

kuka, staubli, krypton, demotool, laserscanner, lias, performer_mk2
and xyPlatform can go to a PMA-specific directory out of the OCL-trunk

i think camera and wrench can stay in OCL, these are also usable for
others, camera only needs OpenCV and a firewire camera, which is quite
general, wrench is usable for everyone who has a PCI interface to a
JR3 sensor.

> Anyway, *every* component should at least meet these standards before
> inclusion in OCL. I'm sure not everything is clear here, help me improve
> this text...
>
> 1. The component can be loaded by the 'DeploymentComponent' (deployer).
> This means each component has a constructor of the form:
> Component(const std::string name) : TaskContext(name),...

agree

> 2. A component that needs a configure() before it can work _must_ be
> started in the PreOperational state:
> Component(const std::string name) : TaskContext(name, PreOperational),...

agree

> 3. If a component has properties, they may be read in the configureHook()
> function from a file or other source. When reading from a file, the default
> file to look for is 'componentname.cpf'. A component attribute may set the
> filename to a user defined value. If no such file is present, and the
> component requires configuration, configureHook() should fail by returning
> false. For example:
> bool configureHook() {
> if ( this->marshalling()->readProperties( this->getName() + ".cpf" ) ==
> false)
> return false;
> return true;
> }

The problem here that if you use the Deployer the component gets
configured twice if a propertyfile is defined in the deployers
configuration.xml

> 4. If a component has properties, they may be written in the cleanupHook()
> to a file or other destination. The default filename is
> 'componentname.cpf'. A component attribute may set the filename to a user
> defined value. For example:
> void cleanupHook() {
> this->marshalling()->writeProperties( this->getName() + ".cpf" )
> }

Can this be done by the Deployer??

> 5. if a component has properties and these properties should not be changed
> by the user at component runtime, the component must use internal copies of
> the property values. The copies are made at startHook(). This allows the
> scenario: read properties from file during configure(), tweak one property,
> start() using the latest values of the properties. stop() again, tweak
> another property, start() again. etc. For example:
> bool startHook() {
> this->mgain = this->gainProp.get(); // only use 'mgain' for calculations
> return true;
> }

agree

> 6. Properties, ports, methods, commands and events are using the online
> documentation infrastructure. For example:
> this->methods()->addMethod( RTT::method("loadLibrary",
> &DeploymentComponent::loadLibrary, this),
> "Load a new library into memory.",
> "Name", "The name of the to be loaded
> library.");
> The RTT allows ports to be not documented, which is only for backwards
> compatibility (RTT 1.0). Please do not use this feature, but use:
> ports()->addPort(_driveValue[i], "Set the drive reference velocity in
> rad/s");

check

> 7. The component and its member functions are documented using non-trivial
> Doxygen comments. Please don't write
> /** Constructor */
> as a comment. Do write
> /** Creates an unconfigured Component. Set the 'ImportantProp' property to
> a valid value and use configure() to inform the component of the new value.
> */

check

> 8. If possible, document the 'scripting' interface of the component using
> @name grouping comments. For example:
> (see
> >1ExecutionAccess.html>) /**
> * @name Script Program Commands
> * @{
> */
> /**
> * Start a Program.
> * @param name The name of the Program.
> */
> bool startProgram(const std::string& name);
>
> /**
> * Stops the execution of a program.
> * @param name The name of the Program.
> */
> bool stopProgram(const std::string& name);
> /** @} */

This is only possible if the function name is exactly the same as the
method/command name which is not always the case. Otherwise it will
only add more confusion

> 9. You must provide a separate document describing a usage scenario of the
> component with at least one figure. This may be done in a component.dox
> (Doxygen style) file or in an component.xml (DocBook) file. The file must
> be included during the 'make doc' pass. For example:
> >yment.html>

I tried to do this for the nAxesComponents. Should we define some "has
to be in there"?

> 10.

10. Supply a deployer configuration xml file and program/statemachine
script that illustrates the usage of the component(s)

Ruben

[OCL] Component guidelines

On Thu, 10 Jan 2008, Peter Soetens wrote:
> In response to Klaas' mail, I'd like to set the standard for acceptable OCL
> C++ components.
>
> There are clearly two groups of components: hardware independent and hardware
> dependent components. I believe both groups should be represented in OCL.
>
> The question raises what, for example, a 'demotool' hardware component is of
> use to the rest of the world. This and other components control custom
> hardware and could only serve as an example. However, examples should be
> clear, not confusing and testable on any platform. That just excludes about
> any hardware component we have in OCL. Most hardware components were written
> at PMA. Maybe they can propose what to do ?

What do you mean by "any" platform, is that platform in the sense of
HW-platform of RTOS. Because, if so, it will indeed be virtually
impossible to find a HW-component suitable for inclusion in OCL

I'm not sure how the naxes components have evolved, but IIRC they
originally were general enough to fit in OCL.

That said, I'm not from PMA (anymore)...

> Anyway, *every* component should at least meet these standards before
> inclusion in OCL. I'm sure not everything is clear here, help me improve this
> text...
>
> 1. The component can be loaded by the 'DeploymentComponent' (deployer).
> This means each component has a constructor of the form:
> Component(const std::string name) : TaskContext(name),...

Clear

> 2. A component that needs a configure() before it can work _must_ be started
> in the PreOperational state:
> Component(const std::string name) : TaskContext(name, PreOperational),...

Clear. Maybe refer to the appropriate section of the component
builders manual here (i.e. section 3.1)

> 3. If a component has properties, they may be read in the configureHook()
> function from a file or other source. When reading from a file, the default
> file to look for is 'componentname.cpf'. A component attribute may set the
> filename to a user defined value. If no such file is present, and the
> component requires configuration, configureHook() should fail by returning
> false. For example:
> bool configureHook() {
> if ( this->marshalling()->readProperties( this->getName() + ".cpf" ) ==
> false)
> return false;
> return true;
> }

Clear.

> 4. If a component has properties, they may be written in the cleanupHook() to
> a file or other destination. The default filename is 'componentname.cpf'. A
> component attribute may set the filename to a user defined value. For
> example:
> void cleanupHook() {
> this->marshalling()->writeProperties( this->getName() + ".cpf" )
> }

Clear.

> 5. if a component has properties and these properties should not be changed by
> the user at component runtime, the component must use internal copies of the
> property values. The copies are made at startHook(). This allows the
> scenario: read properties from file during configure(), tweak one property,
> start() using the latest values of the properties. stop() again, tweak
> another property, start() again. etc. For example:
> bool startHook() {
> this->mgain = this->gainProp.get(); // only use 'mgain' for calculations
> return true;
> }

I don't understand this one.

> 6. Properties, ports, methods, commands and events are using the online
> documentation infrastructure. For example:
> this->methods()->addMethod( RTT::method("loadLibrary",
> &DeploymentComponent::loadLibrary, this),
> "Load a new library into memory.",
> "Name", "The name of the to be loaded
> library.");
> The RTT allows ports to be not documented, which is only for backwards
> compatibility (RTT 1.0). Please do not use this feature, but use:
> ports()->addPort(_driveValue[i], "Set the drive reference velocity in
> rad/s");

OK. Is the above valid for TaskCore's also, and if so, should there
be any representative example of TaskCores in the OCL?

> 7. The component and its member functions are documented using non-trivial
> Doxygen comments. Please don't write
> /** Constructor */
> as a comment. Do write
> /** Creates an unconfigured Component. Set the 'ImportantProp' property to a
> valid value and use configure() to inform the component of the new value.
> */

OK. However, to me this is a non-ocl specific requirement
(i.e. captured in my original mail)

> 8. If possible, document the 'scripting' interface of the component using
> @name grouping comments. For example:
> (see
> )
> /**
> * @name Script Program Commands
> * @{
> */
> /**
> * Start a Program.
> * @param name The name of the Program.
> */
> bool startProgram(const std::string& name);
>
> /**
> * Stops the execution of a program.
> * @param name The name of the Program.
> */
> bool stopProgram(const std::string& name);
> /** @} */

OK.

> 9. You must provide a separate document describing a usage scenario of the
> component with at least one figure. This may be done in a component.dox
> (Doxygen style) file or in an component.xml (DocBook) file. The file must be
> included during the 'make doc' pass. For example:
>

OK.

> 10.

Most, if not all the above rules are HW-agnostic. Maybe we should
also set some more specific rules for HW-_dependent_ components,
e.g. "for inclusion in OCL the HW should be COTS", or the "hw RTOS-
device driver should be easily installable (i.e. come with the RTOS,
or have a package, ...)" , and "the above-mentioned separate document should mention for which RTOS-es the
HW component is working."

ps. Maybe it's time to put the contents of our email-discussions in
the development part of orocos.org?
I'm sure they're not perfect yet, but in time and with practical cases
we can improve them incrementally.

Klaas

Ruben Smits's picture

[OCL] Component guidelines

On Monday January 14 2008 13:51:17 Klaas Gadeyne wrote:
> On Thu, 10 Jan 2008, Peter Soetens wrote:
> > In response to Klaas' mail, I'd like to set the standard for acceptable
> > OCL C++ components.
> >
> > There are clearly two groups of components: hardware independent and
> > hardware dependent components. I believe both groups should be
> > represented in OCL.
> >
> > The question raises what, for example, a 'demotool' hardware component is
> > of use to the rest of the world. This and other components control custom
> > hardware and could only serve as an example. However, examples should be
> > clear, not confusing and testable on any platform. That just excludes
> > about any hardware component we have in OCL. Most hardware components
> > were written at PMA. Maybe they can propose what to do ?
>
> What do you mean by "any" platform, is that platform in the sense of
> HW-platform of RTOS. Because, if so, it will indeed be virtually
> impossible to find a HW-component suitable for inclusion in OCL
>
> I'm not sure how the naxes components have evolved, but IIRC they
> originally were general enough to fit in OCL.

They still do and are almost meet the proposed standards. They are
deployable and documentation is added in the documentation of OCL

[...]

Ruben