Difference between revisions of "Software Development Guide"

From David Vernon's Wiki
Jump to: navigation, search
(Created page with "<strong>WORK IN PROGRESS: DON'T BOTHER READING YET </STRONG> == Overview == Our goal in this document is to summarize all of the the different guidelines on standards for DREA...")
 
(GUI Component Computation and Communication: the FLTK and guiUtilities Libraries)
 
(115 intermediate revisions by the same user not shown)
Line 1: Line 1:
<strong>WORK IN PROGRESS: DON'T BOTHER READING YET </STRONG>
+
 
 
== Overview ==
 
== Overview ==
Our goal in this document is to summarize all of the the different guidelines on standards for DREAM software to make it easier for developers to find out what they need to do so that their code conforms to best practice (e.g. configuration management, parameter usage,  port naming and renaming, use of RFModule helper class, use of threads, graceful shut-down, run-time interaction, documentation, coding standards, application description, etc).  A full list of all the resources that were used in putting together this summary is provided at the end.
 
  
 +
This guide describes two examples of what is involved when developing a YARP-based component that is compliant with recommended standards for software engineering.
  
To help bring all this material together, we will develop a simple example module to highlight the key issues.  The code for the complete module is also provided at the end.
+
The first example, <code>protoComponent</code>, implements some very simple image processing and analysis (binary segmentation using a supplied threshold and then count the number of foreground pixels).
  
 +
The second example, <code>protoComponentGUI</code>, explains how to write a component that implements a simple graphic use interface.  In this case, the GUI allows the user to set the threshold with a slider widget and then sends the threshold to  <code>protoComponent</code>.  It receives some statistics from <code>protoComponent</code>, specifically the number of foreground pixels and the current time, and writes them to a text display. It also receives the binary image from  <code>protoComponent</code> and displays it along with the original colour image that it receives from the source that also feeds  <code>protoComponent</code>.
  
If you want to jump in the deep end, start by reading
+
Both examples are accompanied by a test application, again adhering to the recommended standards.
  
 +
=== File Organization ===
  
* [http://wiki.icub.org/iCub/main/dox/html/module_standards.html Module Standards] to find out the minimal responsibilities of your module with respect to handling parameters and ports, as well configuration and shut down. Then read the following tutorials:
+
As noted in the [[Mandatory Standards for File Organization]],  the implementation of a typical CINDY component comprises four files. These are the interface file and three implementation files:
  
* [[Resource finder overview]]
+
* The interface file is a header file, e.g. <code>protoComponent.h</code>, with the class declarations, method prototype declarations, and function prototype declarations, but no method or function implementations.  It also contains the Doxygen documentation comments explaining the purpose and usage of the component (see [[Mandatory Standards for Internal Documentation]]).
 +
*The implementation files contains the source code for the implementation of each class method (C++) or the source code of each function (C).  For convenience, the implementation is separated in three files:
 +
# The first source code file — e.g. <code>protoComponentMain.cpp</code> — contains the <code> main()</code>  function that instantiates the module object and calls the <code>runModule</code> method to effect the configuration, coordination, computation, and communication for that component.
 +
# The second source code file — e.g. <code>protoComponentConfiguration.cpp</code> — contains the code that handles the component’s configuration and coordination functionality.
 +
# The third source code file — e.g. <code>protoComponentComputation.cpp</code> — contains the code that handles the component’s computation and communication functionality.
  
* [http://wiki.icub.org/iCub/main/dox/html/icub_resource_finder_basic.html How to organize the command line parameters of your modules]
+
Therefore,  the four <code>protoComponent</code> files are:
  
* [http://wiki.icub.org/iCub/main/dox/html/icub_resource_finder_advanced.html Organizing Parameters: Advanced Tutorial]
+
protoComponent.h
 +
protoComponentMain.cpp
 +
protoComponentConfiguration.cpp
 +
protoComponentComputation.cpp
  
* [http://wiki.icub.org/iCub/main/dox/html/icub_tutorial_module.html Using the module helper class to write a program]
+
and the four <code>protoComponentGUI</code> files are:
  
 +
protoComponentGUI.h
 +
protoComponentGUIMain.cpp
 +
protoComponentGUIConfiguration.cpp
 +
protoComponentGUIComputation.cpp
  
The fourth of these tutorials is essential reading and introduces you to the [http://wiki.icub.org/yarpdoc/d9/d26/classyarp_1_1os_1_1RFModule.html RFModule] class, the mandatory starting point when developing DREAM modules.  Note that we are moving away from using [http://wiki.icub.org/yarpdoc/d1/d03/classyarp_1_1os_1_1Module.html Module] class as RFModule offers similar functionality to Module, but it adds support for the ResourceFinder class.
+
All of these files should be placed in the <code>src</code> directory.
  
 +
Note that in a Component-Based Software Engineering (CBSE) project, such as CINDY, the source code application file is replaced by the application script file or application XML file that runs the various components and connects them together in a working system (see [[#Application Description]]).
  
Alternatively, read through this page and then refer to the documents above for more detail and clarification, if necessary.
+
=== Example Code ===
  
== The <code>RFModule</code> Class ==
+
All the code for these examples is available in the CINDY software repository.  For convenience, you can also review the code here:
  
The starting point in writing a module for the DREAM repository is to develop a sub-class of the [http://wiki.icub.org/yarpdoc/d9/d26/classyarp_1_1os_1_1RFModule.html yarp::os::RFModule] class.
+
* [[The protoComponent Example | <code>protoComponent</code> source code]]
 +
* [[The protoComponentTEST Example | <code>protoComponentTEST.xml</code> application]]
 +
* [[The protoComponentGUI Example | <code>protoComponentGUI</code> source code]]
 +
* [[The protoComponentGUITEST Example | <code>protoComponentGUITEST.xml</code> application]]
  
 +
=== How This Guide Is Organized ===
  
First, we define a sub-class, or derived class, of the <code>yarp::os::RFModule</code> class.  The module's variables - ''and specifically the module's parameters and ports'' - go in the private data members part and you need to override three methods:
+
There are four main parts to this guide, in addition to this overview, some focussing on the <code>protoComponent</code> example and others on the <code>protoComponentGUI</code> example.
  
 +
====  Component Configuration and Coordination: the <code>RFModule</code> Class ====
 +
 +
We begin with the functionality associated with configuration and coordination, i.e. with the <code>protoComponentConfiguration.cpp</code> and  <code>protoComponent.h</code> files.  This functionality revolves around the <code>RFModule</code> class.  The <code>protoComponentGUIConfiguration.cpp</code> and  <code>protoComponentGUI.h</code> files have essentially the same structure.
 +
 +
This section also deals with the  <code>main()</code> function, i.e. with the  <code>protoComponentApplication.cpp</code> file.  It shows how to instantiate a module derived from the <code>RFModule</code> class, set the default configuration file and path for the resource finder, and run the module.  This allows the component to be configured using the resource finder. 
 +
 +
Once this is done, the derived module then instantiates a <code>Thread</code>  or a  <code>RateThread</code> object and launches it, passing to it as arguments all the relevant resources (e.g. port names and parameter values) located by the resource finder.
 +
 +
Finally, it is also responsible for shutting down the thread gracefully by stopping the thread, interrupting any port communications, and closing the ports.
 +
 +
====  Component  Computation and Communication: the <code>Thread</code> and  <code>RateThread</code> Classes  ====
 +
 +
We then address the functionality associated with computation and communication, i.e. with the  <code>protoComponentComputation.cpp</code> and  <code>protoComponent.h</code> files.  This functionality revolves around the  <code>Thread</code>  and  <code>RateThread</code> classes: how to access the parameters passed to it from the derived <code>RFModule</code> object and how to perform some useful work.
 +
 +
====  GUI Component Computation and Communication: the <code>FLTK</code> and  <code>guiUtilities</code> Libraries  ====
 +
 +
We now show how you can write your own graphic user interface for the <code>protoComponent</code> component.  This will be implemented as a separate stand-along component <code>protoComponentGUI</code>. As noted above, the functionality associated with configuration and coordination, i.e. with the <code>protoComponentGUIConfiguration.cpp</code> and  <code>protoComponentGUI.h</code> files, is essentially the same as for the <code>protoComponent</code> example. Again, this functionality revolves around the <code>RFModule</code> class.
 +
 +
Instead, this section addresses the functionality associated with computation and communication, i.e. with the  <code> protoComponentGUIComputation.cpp </code> and  <code>protoComponent.h </code> files.  Again, the functionality revolves around the  <code>Thread</code>  and  <code>RateThread</code> classes but here we explain how to configure the graphic user interface with the ''FLTK'' and  ''guiUtilities'' libraries.
 +
 +
==== Test Applications  ====
 +
 +
This section describes two test applications. 
 +
 +
The first test application shows how to configure and run a simple application to use the <code>protoComponent</code> by connecting it to other components that provide input images and display the output images. This application uses <code>yarpview</code> modules to view the images. The threshold is modified online by sending commands  to <code>protoComponent</code> from the command line in a terminal window.
 +
 +
The second test application shows how to configure and run a simple application to use <code> protoComponent</code>  and <code> protoComponentGUI</code> together.  In this case, the images are displayed in the GUI rather than <code>yarpview</code> displays and the threshold is modified interactively using the GUI controls.
 +
 +
==  Component Configuration and Coordination: The <code>RFModule</code> Class ==
 +
 +
The starting point in writing any CINDY component is to develop a sub-class of the [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1RFModule.html  yarp::os::RFModule] class. 
 +
 +
First, we define a sub-class, or derived class, of the <code>yarp::os::RFModule</code> class.  The module's variables - ''and specifically the module's parameters and ports'' - go in the private data members part and you need to override three methods:
  
 
* <code>bool configure(); </code>
 
* <code>bool configure(); </code>
 
* <code>bool interruptModule(); </code>
 
* <code>bool interruptModule(); </code>
 
* <code>bool close(); </code>
 
* <code>bool close(); </code>
 
  
 
We will see later that there are three other methods which can be useful to override:
 
We will see later that there are three other methods which can be useful to override:
 
  
 
* <code>bool respond();</code>
 
* <code>bool respond();</code>
Line 46: Line 95:
 
* <code>bool updateModule();</code>
 
* <code>bool updateModule();</code>
  
 +
In the following, we assume we are writing a module named <code>protoComponent</code>.  This module will be implemented as a sub-class [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1RFModule.html yarp::os::RFModule] called <code>ProtoComponent</code> (it is a capital P because it is a sub-class).  For convenience, the header comments have been removed.
  
In the following, we assume we are writing a module named <code>myModule</code>. This module will be implemented as a sub-class [http://wiki.icub.org/yarpdoc/d9/d26/classyarp_1_1os_1_1RFModule.html yarp::os::RFModule] called <code>MyModule</code> (capital M because we are going to create a sub-class).
+
  /** @file protoComponent.h Interface file for the example CINDY component */
 
+
 
  #include <iostream>
 
  #include <iostream>
 
  #include <string>
 
  #include <string>
 +
 +
#include <yarp/sig/all.h>
 +
#include <yarp/os/all.h>
 
  #include <yarp/os/RFModule.h>
 
  #include <yarp/os/RFModule.h>
 
  #include <yarp/os/Network.h>
 
  #include <yarp/os/Network.h>
 +
#include <yarp/os/Thread.h>
 
    
 
    
 
  using namespace std;
 
  using namespace std;
 
  using namespace yarp::os;  
 
  using namespace yarp::os;  
 +
using namespace yarp::sig;
 +
 
 +
class ProtoComponentThread : public Thread {
 
   
 
   
  class MyModule:public RFModule
+
  private:
  {
+
   
     /* module parameters */
+
     /* class variables */
 +
 +
    bool              debug;
 +
    int                x, y;
 +
    PixelRgb          rgbPixel;
 +
    ImageOf<PixelRgb> *image;
 +
    int              *thresholdValue; 
 +
    VectorOf<int>    *thresholdVector;
 +
    int              numberOfForegroundPixels;
 +
 +
    /* thread parameters: they are pointers so that they refer to the original variables in protoComponent */
 +
 +
    BufferedPort<ImageOf<PixelRgb> > *imagePortIn;
 +
    BufferedPort<VectorOf<int> >    *thresholdPortIn;
 +
    BufferedPort<ImageOf<PixelRgb> > *imagePortOut;
 +
    BufferedPort<Bottle>            *statisticsPortOut;
 +
 
 +
 +
  public:
 
    
 
    
 +
    /* class methods */
 +
 
 +
    ProtoComponentThread(BufferedPort<ImageOf<PixelRgb> > *imageIn,
 +
                          BufferedPort<VectorOf<int> >    *thresholdIn,
 +
                          BufferedPort<ImageOf<PixelRgb> > *imageOut,
 +
                          BufferedPort<Bottle>            *statisticsOut,
 +
                          int *threshold );
 +
    bool threadInit();   
 +
    void threadRelease();
 +
    void run();
 +
};
 +
 +
 +
class ProtoComponent:public RFModule {
 +
 +
    /* module parameters */
 +
 +
    string moduleName;
 +
    string imageInputPortName;
 +
    string thresholdInputPortName;
 +
    string imageOutputPortName;
 +
    string statisticsOutputPortName; 
 +
    string handlerPortName;
 +
    string cameraConfigFilename;
 +
    float  fxLeft,  fyLeft;          // focal length
 +
    float  fxRight, fyRight;        // focal length
 +
    float  cxLeft,  cyLeft;          // coordinates of the principal point
 +
    float  cxRight, cyRight;        // coordinates of the principal point
 +
    int    thresholdValue;
 +
 
     /* class variables */
 
     /* class variables */
 +
 +
    BufferedPort<ImageOf<PixelRgb> > imageIn;      // example image input port
 +
    BufferedPort<VectorOf<int> >    thresholdIn;  // example vector input port
 +
    BufferedPort<ImageOf<PixelRgb> > imageOut;      // example image output port
 +
    BufferedPort<Bottle>            statisticsOut; // example bottle output port
 +
    Port handlerPort;                              // a port to handle interactive messages (also uses bottles)
 +
 +
    /* pointer to a new thread to be created and started in configure() and stopped in close() */
 +
 +
    ProtoComponentThread *protoComponentThread;
 
   
 
   
 
  public:
 
  public:
   
+
 
 
     bool configure(yarp::os::ResourceFinder &rf); // configure all the module parameters and return true if successful
 
     bool configure(yarp::os::ResourceFinder &rf); // configure all the module parameters and return true if successful
 
     bool interruptModule();                      // interrupt, e.g., the ports  
 
     bool interruptModule();                      // interrupt, e.g., the ports  
 
     bool close();                                // close and shut down the module
 
     bool close();                                // close and shut down the module
     bool respond();
+
     bool respond(const Bottle& command, Bottle& reply);
 
     double getPeriod();  
 
     double getPeriod();  
 
     bool updateModule();
 
     bool updateModule();
  }
+
  };
+
We will deal with the various issues of implementing the module under several headings, addressing configuration, doing some work, run-time interaction, graceful shut-down, standards, and application description.
+
  
== Configuration ==
+
Here we deal with the various issues of implementing the module, particularly configuration of the component from external parameters and files, and run-time interaction.
  
By configuration, we mean the ability to specify the way that a given module is usedThere are two aspects to this:
+
The actual work to be done by the component is accomplished by another sub-class  of a <code>Thread</code> classThe definition of this sub-class is also included in the interface header file, e.g. <code>protoComponent.h</code> but the implementation is effected in a separate source file, e.g. <code>protoComponentComputation.cpp</code>.
# how the module is presented (i.e. which particular interfaces are used: the names of ports used, the name of the configuration file, the path to the configuration file, the name of the module, and the name of the robot) and
+
# the module parameters that govern its behaviour (e.g. thresholds, set-points, and data files)
+
We refer to these collectively as resources. Typically, the configuration file name, the configuration file path (called the context), the module name, and the robot name are specified as command-line parameters, while all the remaining resources, including the names of the ports, are typically specified in the configuration file.
+
  
 +
Perhaps the trickiest part of writing the software to implement a component is understanding the way that the <code>RFModule</code> and <code>Thread</code> share the work between them and how they interact.  That's exactly what we will explain in to following, once we have covered how the <code>RFModule</code> object handles all the configuration and coordination functionality.
  
What's important to realize, however, is that ''all'' resources are handled the same way using the ResourceFinder which not only greatly simplifies the process of finding the resources but also simplifies the process of parsing themThere is more detail on handling resources in [[Configuration and resource files]].   
+
First, some clarification. By ''configuration'' we mean the ability to specify the way that a given component is used.  There are two aspects to this:
 +
# How the component is presented (i.e. which particular interfaces are used: the names of ports used, the name of the configuration file, the path to the configuration file, the name of the component, and the name of the robot) and
 +
# The component parameters that govern its behaviour (e.g. thresholds, set-points, and data files)
 +
We refer to these collectively as resourcesTypically, the configuration file name, the configuration file path (called the context), the component name, and the robot name are specified as command-line parameters, while all the remaining resources, including the names of the ports, are typically specified in the configuration file.   
  
 +
Note that ''all'' resources are handled the same way using the ''ResourceFinder'' which not only greatly simplifies the process of finding the resources but also simplifies the process of parsing them.
  
 
It's worth noting that parameters that are specified in the configuration file can also be specified in the command-line if you wish.  The reverse is also true, with some restrictions (e.g. it only makes sense to specify the configuration file and the configuration file path on the command-line).  Finally, modules should be written so that default values are provided for all resources so that the module can be launched without any parameters. Again, the ResourceFinder makes it easy to arrange this.
 
It's worth noting that parameters that are specified in the configuration file can also be specified in the command-line if you wish.  The reverse is also true, with some restrictions (e.g. it only makes sense to specify the configuration file and the configuration file path on the command-line).  Finally, modules should be written so that default values are provided for all resources so that the module can be launched without any parameters. Again, the ResourceFinder makes it easy to arrange this.
 
  
 
Right now, what's important to grasp is that all these configuration issues are implemented by  
 
Right now, what's important to grasp is that all these configuration issues are implemented by  
  
 +
* '''Instantiating your component as a derived sub-class of <code>RFModule</code> in the <code>main()</code> function (e.g. in <code>protoComponentMain.cpp</code>),
  
* preparing the Resource Finder in the <code>main</code> function by setting the default configuration file and its path,  
+
* '''Preparing the ''ResourceFinder'' in the <code>main()</code> function by setting the default configuration file and its path,'''
* overriding the <code>yarp::os::RFModule::configure()</code> method to parse all the parameters from the command-line and the configuration file.
+
  
 +
* '''Overriding the <code>yarp::os::RFModule::configure()</code> method (e.g. in <code>protoComponentConfiguration.cpp</code>) to parse all the parameters from the command-line and the configuration file.'''
  
The following sections explain the implementation details of each aspect of this configuration. 
+
* '''Launching your component by calling the <code>yarp::os::RFModule::runModule()</code> method from <code>main()</code>,
  
 +
The following sections explain the implementation details of each aspect of this set-up and configuration. 
  
=== Essential Command-line Parameters ===
+
=== Instantiating a Derived Sub-Class of <code>RFModule</code>, Configuring the Resource Finder, and Running the Module ===
  
==== Configuration File ====
+
The  <code>main()</code> function in the  <code>protoComponentMain.cpp</code> file is responsible for instantiating a module derived from the <code>RFModule</code> class, setting the default configuration file and path for the resource finder, and running the module.  This allows the component to be configured using the resource finder (something that is actually accomplished by the code in <code>protoComponentConfiguration.cpp</code>). 
  
Configuration can be changed by changing configuration files. The configuration file which the module reads can be specified as a command line option.
+
/* protoComponentMain.cpp Application file for the example CINDY component */
 +
 +
int main(int argc, char * argv[])
 +
{
 +
  /* initialize yarp network */
 +
 
 +
  Network yarp;
 +
 
 +
  /* create your module */
 +
 
 +
  ProtoComponent protoComponent;
 +
 
 +
  /* prepare and configure the resource finder */
 +
 
 +
  ResourceFinder rf;
 +
  rf.setVerbose(true);
 +
  rf.setDefaultConfigFile("protoComponent.ini");          // can be overridden by --from parameter
 +
  rf.setDefaultContext("protoComponent/configuration");  // can be overridden by --context parameter
 +
  rf.configure("CINDY_ROOT", argc, argv);                // environment variable with root of configuration path
 +
 
 +
  /* run the module: runModule() calls configure first and, if successful, it then runs */
 +
 
 +
  protoComponent.runModule(rf);
 +
 
 +
  return 0;
 +
}
  
--from myModule.ini
+
There are a few important points to notice in the code above.  
  
The module should set a default configuration file using <code>yarp::os::ResourceFinder::setDefaultConfigFile("myModule.ini")</code>. This should be done in the <code>main()</code> function before running the module.
 
  
This is  overridden by the <code>--from</code> parameter.
+
* Initialization of the configuration file in the resource finder object
  
The .ini file should usually be placed in the <code>$DREAM_ROOT/app/myModule/conf</code> sub-directory.
+
* Initialization of the path to the configuration file in the resource finder object
  
 +
* Initialization of the environmental variable that defines the root of the configuration path in the resource finder object
  
==== Context ====
+
* The <code>runModule</code> method is called  to launch the module and do the configuration using the resource finder object passed as an argument
  
The relative path from <code>$DREAM_ROOT/app/</code>  to the directory containing the configuration file is specified from the command line by 
 
  
--context  myModule/conf  
+
The first two require some additional explanation which we provide next.  
  
The module should set a default context using  <code>yarp::os::ResourceFinder::setDefaultContext("myModule/conf")</code>. 
+
==== Configuration File ====
This should be done in the <code>main()</code> function before running the module.
+
  
This is overridden by the <code>--context</code> parameter.
+
Configuration can be changed by changing configuration files. The configuration file which the component reads can be specified as a command line option.
  
 +
--from protoComponent.ini
  
==== Module Name and Port Names ====
+
The component should set a default configuration file using <code>yarp::os::ResourceFinder::setDefaultConfigFile("protoComponent.ini")</code>. This should be done in the <code>main()</code> function before running the module.
  
 +
The value set by this method is overridden by the <code>--from</code> parameter (specified either during the command-line invocation or in the component configuration file; the command-line has priority over the configuration file if both are specified).
  
'''Warning:'''  the naming convention for the --name, --robot, and port name arguments in key-value pairs has changed. The arguments of --name and --robot '''do not''' having a leading "/" prefix and port name arguments '''always''' have a leading "/" prefix ... exactly the opposite of what was considered acceptable practice in the past.
+
The .ini file should usually be placed in the <code>$CINDY_ROOT/release/components/protoComponent/config</code> sub-directory.
  
 +
==== Context ====
  
It should be possible to specify the names of any ports created by a module via configuration.  There are two aspects to this: the stem of the port name and the port name itself.   
+
The relative path from <code>$CINDY_ROOT/release</code>  to the directory containing the configuration file is specified from the command line by 
 +
 
 +
--context  components/protoComponent/config
 +
 
 +
The module should set a default context using  <code>yarp::os::ResourceFinder::setDefaultContext("components/protoComponent/config")</code>. 
 +
This should be done in the <code>main()</code> function  in <code>protoComponentMain.cpp</code> before launching the component.
 +
 
 +
This is overridden by the <code>--context</code> parameter (again, specified either during the command-line invocation or in the component configuration file; the command-line has priority over the configuration file if both are specified).
 +
 
 +
=== Configuration: Overriding the <code>yarp::os::RFModule::configure()</code> method  ===
 +
 
 +
The method that overrides <code>yarp::os::RFModule::configure()</code> is defined in <code>protoComponentConfiguration.cpp</code>.  It uses the resource finder to parse all the parameters from the command-line and the configuration file and assign values appropriately.
 +
 
 +
The key thing to keep in mind here is that it must be possible to  ''externally'' reconfigure how the component interfaces with other components without having to modify any source code.  This is why so much information is required when starting up the component and why the resource finder is so useful and important.
 +
 
 +
==== Module Name and Port Names ====
 +
 
 +
You should ensure that it is possible to specify the names of any ports created by a module via configuration.  There are two aspects to this: the stem of the port name and the port name itself.   
  
 
A command-line option of  
 
A command-line option of  
Line 140: Line 299:
 
sets the name of the module and will cause the module to use "/altName" as a stem for all port names provided the port names are generated using the <code>yarp::os::RFModule::getName()</code> method.  Note that he leading "/" prefix has to be added explicitly to the module name to create the port name.
 
sets the name of the module and will cause the module to use "/altName" as a stem for all port names provided the port names are generated using the <code>yarp::os::RFModule::getName()</code> method.  Note that he leading "/" prefix has to be added explicitly to the module name to create the port name.
  
 
+
The module should set a default name (and, hence, a default stem) using  <code>yarp::os::RFModule::setName("protoComponent")</code>.  
The module should set a default name (and, hence, a default stem) using  <code>yarp::os::RFModule::setName("myModule")</code>.  
+
 
+
  
 
This is overridden by the <code>--name</code> parameter but you must check for this parameter and call <code>setName()</code> accordingly, e.g.
 
This is overridden by the <code>--name</code> parameter but you must check for this parameter and call <code>setName()</code> accordingly, e.g.
Line 149: Line 306:
 
    
 
    
 
  moduleName = rf.check("name",  
 
  moduleName = rf.check("name",  
               Value("myModule"),  
+
               Value("protoComponent"),  
 
               "module name (string)").asString();     
 
               "module name (string)").asString();     
 
   
 
   
Line 156: Line 313:
 
The port names should be specified as parameters, typically as key-value pairs in the <code>.ini</code> configuration file, e.g.  
 
The port names should be specified as parameters, typically as key-value pairs in the <code>.ini</code> configuration file, e.g.  
  
  myInputPort  /image:i
+
  imageInputPort    /image:i
  myOutputPort  /image:o
+
  imageOutputPort  /image:o
  
 
These key-value pairs can also be specified as command-line parameters, viz:  
 
These key-value pairs can also be specified as command-line parameters, viz:  
<code>--myInputPort /image:i  --myOutputPort /image:o</code>
+
<code>--imageInputPort /image:i  --imageOutputPort /image:o</code>
  
The module should set a default port name using  the ResourceFinder, e.g using <code>yarp::os::ResourceFinder::check();</code>
+
The component should set a default port name using  the ResourceFinder, e.g using <code>yarp::os::ResourceFinder::check();</code>
  
 
For example
 
For example
Line 168: Line 325:
 
  string inputPortName  = "/";
 
  string inputPortName  = "/";
 
         inputPortName += getName(
 
         inputPortName += getName(
                         rf.check("myInputPort",
+
                         rf.check("imageInputPort",
 
                         Value("/image:i"),
 
                         Value("/image:i"),
 
                         "Input image port (string)").asString()
 
                         "Input image port (string)").asString()
 
                         );
 
                         );
  
will assign to <code>inputPortName</code> the value <code>/altName/image:i</code> if <code>--name altName</code> is specified as a parameter.  Otherwise, it would assign <code>/myModule/image:i</code>  On the other hand, it would assign <code>/myModule/altImage:i</code> if the key-value pair <code>myInputPort /altImage:i</code> was specified (either in the <code>.ini</code> file or as a command-line parameter) but not the <code>--name altName</code>
+
will assign to <code>inputPortName</code> the value <code>/altName/image:i</code> if <code>--name altName</code> is specified as a parameter.  Otherwise, it would assign <code>/protoComponent/image:i</code>  On the other hand, it would assign <code>/protoComponent/altImage:i</code> if the key-value pair <code>myInputPort /altImage:i</code> was specified (either in the <code>.ini</code> file or as a command-line parameter) but not the <code>--name altName</code>
 
+
  
 
When providing the names of ports as parameter values (whether as a default value in <code>ResourceFinder::check</code>, as a value in the key-value list in the <code>.ini</code> configuration file, or as a command line argument), you always include the leading <code>/</code>.
 
When providing the names of ports as parameter values (whether as a default value in <code>ResourceFinder::check</code>, as a value in the key-value list in the <code>.ini</code> configuration file, or as a command line argument), you always include the leading <code>/</code>.
  
 
+
All this code goes in the <code>configure()</code> method in <code>protoComponentConfiguration.cpp</code>.
All this code goes in the <code>configure()</code> method.
+
+
  
 
==== Which Parameters Are Parsed Automatically? ====
 
==== Which Parameters Are Parsed Automatically? ====
  
 
Parsing the <code>--from</code> and <code>--context</code> parameters is handled automatically by the <code>RFModule</code> but <code>--name</code> and <code>--robot</code> must be handled explicitly.
 
Parsing the <code>--from</code> and <code>--context</code> parameters is handled automatically by the <code>RFModule</code> but <code>--name</code> and <code>--robot</code> must be handled explicitly.
 
  
 
As noted above, you would handle the <code>--name</code> parameter by using <code>ResourcFinder::check()</code> to parse it and get the parameter value, then user <code>setName()</code> to set it.  You should do this before proceeding to process any port name parameters, otherwise the wrong stem will be used when constructing the port names from the parameter values.
 
As noted above, you would handle the <code>--name</code> parameter by using <code>ResourcFinder::check()</code> to parse it and get the parameter value, then user <code>setName()</code> to set it.  You should do this before proceeding to process any port name parameters, otherwise the wrong stem will be used when constructing the port names from the parameter values.
  
 +
==== Configuration File Parameters ====
  
Typically, you would handle the <code>--robot</code> parameter by using ResourceFinder to parse the <code>--robot</code> or <code>--name</code> parameter to get the root of the port name and then construct the full port name by appending the specific part of the robot required. An example is provided below.
+
The configuration file, typically named <code>protoComponent.ini</code> and located in the <code>$CINDY_ROOT/release/components/protoComponent/config</code> directory, contains a key-value list: a list of pairs of keywords (configuration parameter names) and values (configuration parameter values), e.g.
  
 
+
  imageInputPort  /altImage:i
=== Configuration File Parameters ===
+
  imageOutputPort  /altImage:o
The configuration file, typically named <code>myModule.ini</code> and located in the <code>$DREAM_ROOT/app/myModule/conf</code> directory, contains a key-value list: a list of pairs of keywords (configuration parameter names) and values (configuration parameter values), e.g.
+
 
+
myInputPort /altImage:i
+
  myOutputPort /altImage:o
+
 
  threshold 9
 
  threshold 9
 
  ...
 
  ...
  
These parameters are parsed using the [http://wiki.icub.org/yarpdoc/d9/ddf/classyarp_1_1os_1_1ResourceFinder.html <code>ResourceFinder</code>] within an <code>RFModule</code> object (i.e. by methods inherited by your module such as
+
These parameters are parsed using the [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1ResourceFinder.html <code>ResourceFinder</code>] within an <code>RFModule</code> object (i.e. by methods inherited by your module such as
[http://wiki.icub.org/yarpdoc/d2/d0c/classyarp_1_1os_1_1Searchable.html#818029558a2d8772db43a5a3c8b61125 <code>yarp::os::Searchable::check()</code>]).
+
[http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1Searchable.html <code>yarp::os::Searchable::check()</code>]).
 +
 
  
 
Typically, key-value pairs specify the parameters and their values that govern the behaviour of the module, as well as the names of the module ports, should you wish to rename them.
 
Typically, key-value pairs specify the parameters and their values that govern the behaviour of the module, as well as the names of the module ports, should you wish to rename them.
  
=== Other Configuration Files ===
+
==== Other Configuration Files ====
  
Apart from processing the parameters in the configuration file <code>myModule.ini</code>, it's often necessary to access configuration
+
Apart from processing the parameters in the configuration file <code>protoComponent.ini</code>, it's often necessary to access configuration
 
data in other files. For example, you might want to read the intrinsic camera parameters from a camera calibration file.
 
data in other files. For example, you might want to read the intrinsic camera parameters from a camera calibration file.
Let's assume this configuration file is called <code>robotEyes.ini</code> and we wish to extract the principal points of the left and right cameras.  The coordinates of the principle points, and other intrinsic camera parameters, are generated by the [http://wiki.icub.org/iCub/dox/html/group__icub__camcalibconf.html camera calibration module] and are stored as a sequence of key-value pairs:
+
Let's assume this configuration file is called <code>cameras.ini</code> and we wish to extract the principal points of the left and right cameras.  The coordinates of the principle points, and other intrinsic camera parameters, are stored as a sequence of key-value pairs:
  
 
  cx 157.858
 
  cx 157.858
Line 231: Line 382:
 
So, to read these two pairs of coordinates, we need to  
 
So, to read these two pairs of coordinates, we need to  
  
* find the name of the file (e.g. <code>robotEyes.ini</code>)
+
* find the name of the file (e.g. <code>cameras.ini</code>)
 
* locate the file (i.e. get its full path)
 
* locate the file (i.e. get its full path)
 
* open the file and read its content
 
* open the file and read its content
Line 237: Line 388:
 
* read the respective <code>cx</code> and <code>cy</code> key values.
 
* read the respective <code>cx</code> and <code>cy</code> key values.
  
All of this is accomplished straightforwardly with the [http://wiki.icub.org/yarpdoc/d9/ddf/classyarp_1_1os_1_1ResourceFinder.html <code>ResourceFinder</code>] and [http://wiki.icub.org/yarpdoc/da/d1f/classyarp_1_1os_1_1Property.html <code>Property</code>] classes.
+
 
 +
All of this is accomplished straightforwardly with the [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1ResourceFinder.html <code>ResourceFinder</code>] and [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1Property.html <code>Property</code>] classes.
 +
 
  
 
The first step is to get the name of the configuration file.  This will typically be one of the key-value pairs in the module  
 
The first step is to get the name of the configuration file.  This will typically be one of the key-value pairs in the module  
configuration file <code>myModule.ini</code>, e.g.  
+
configuration file <code>protoComponent.ini</code>, e.g.  
  
  cameraConfig robotEyes.ini
+
  cameraConfig cameras.ini
  
so that it can be read in exactly the same way as the other parameters in the previous section, e.g. using [http://wiki.icub.org/yarpdoc/d2/d0c/classyarp_1_1os_1_1Searchable.html#818029558a2d8772db43a5a3c8b61125 <code>yarp::os::Searchable::check()</code>].
+
so that it can be read in exactly the same way as the other parameters in the previous section, e.g. using [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1Searchable.html#a109f36a33b39972b0797110304380003 <code>yarp::os::Searchable::check()</code>].
  
The full path can then be determined by the [http://wiki.icub.org/yarpdoc/d9/ddf/classyarp_1_1os_1_1ResourceFinder.html#355586da9ad41565a2a0daa36e7ec2e1 <code>yarp::os::ResourceFinder::findFile()</code>] method.
+
The full path can then be determined by the [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1ResourceFinder.html#a73f64f1a452732ef8beb60984af0a99b <code>yarp::os::ResourceFinder::findFile()</code>] method.
  
The contents of this file can then be read into a [http://wiki.icub.org/yarpdoc/da/d1f/classyarp_1_1os_1_1Property.html <code>Property</code>] object using the [http://wiki.icub.org/yarpdoc/da/d1f/classyarp_1_1os_1_1Property.html#06c34c056e399f1cad1ad74b3a147a76 <code>yarp:os:Property::fromConfigFile()</code>] method.
+
The contents of this file can then be read into a [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1Property.html <code>Property</code>] object using the [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1Property.html#a8048b872a66d398d1baed6aed1f301b2 <code>yarp:os:Property::fromConfigFile()</code>] method.
  
Locating the required group (e.g. <code>CAMERA_CALIBRATION_LEFT</code>) is accomplished with the [http://wiki.icub.org/yarpdoc/da/d1f/classyarp_1_1os_1_1Property.html#ed956fea82f3b54bc846946c1f836ccb<code>yarp: os:Property::findGroup()</code>] method.     
+
Locating the required group (e.g. <code>CAMERA_CALIBRATION_LEFT</code>) is accomplished with the [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1Property.html#aa819ea2ae0d680a2e2bf899c22900e5b <code>yarp: os:Property::findGroup()</code>] method.     
  
This method returns a [http://wiki.icub.org/yarpdoc/d3/d3e/classyarp_1_1os_1_1Bottle.html <code>Bottle</code>] with the full key-value list under this group.  This list can then be searched for the required key and value using the [http://wiki.icub.org/yarpdoc/d2/d0c/classyarp_1_1os_1_1Searchable.html#818029558a2d8772db43a5a3c8b61125 <code>yarp::os::Searchable::check()</code>] method, as before.
+
This method returns a [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1Bottle.html <code>Bottle</code>] with the full key-value list under this group.  This list can then be searched for the required key and value using the [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1Searchable.html#a109f36a33b39972b0797110304380003 <code>yarp::os::Searchable::check()</code>] method, as before.
  
Please refer to the <code>myModule</code> example for further details.
+
=== Run-time Interaction ===
  
=== An Example of how to Configure the Module ===
+
==== The <code>respond()</code> Method ====
  
The following simple module shows how to handle the foregoing configuration issues.
+
Often, it is very useful for a user or another module to send commands to control the behaviour of the module, e.g. interactively changing parameter values.  
  
 +
We accomplish this functionality for the <code>yarp::os::RFModule</code> by overridding the <code>yarp::os::RFModule::respond()</code> method which can then be configured to receive messages from either a port (typically named <code>/protoComponent</code>) or the terminal. This is effected by the <code>yarp::os::RFModule::attach(port)</code> and <code>yarp::os::RFModule::attachTerminal()</code> methods, respectively. Attaching both the port and the terminal means that commands from both sources are then handled in the same way.
  
 +
==== An example of how to change module parameters at run-time ====
 +
 +
In the following example, we handle three commands:
 +
 +
* help
 +
* quit
 +
* set thr <n>  ... set the threshold (where <n> is an integer number)
 +
 +
Apart from the way that the commands are parsed and the form of the reply, the key thing to note here is the fact that the value of <code>ProtoComponent::thresholdValue</code> is updated. Since <code>protoComponent</code> references this variable, it too is updated and the updated value is used in the thread.
 +
 +
bool ProtoComponent::respond(const Bottle& command, Bottle& reply)
 +
{
 +
  string helpMessage =  string(getName().c_str()) +
 +
                        " commands are: \n" + 
 +
                        "help \n" +
 +
                        "quit \n" +
 +
                        "set thr <n> ... set the threshold \n" +
 +
                        "(where <n> is an integer number) \n";
 +
 +
  reply.clear();
 +
 +
  if (command.get(0).asString()=="quit") {
 +
        reply.addString("quitting");
 +
        return false;   
 +
    }
 +
    else if (command.get(0).asString()=="help") {
 +
      cout << helpMessage;
 +
  reply.addString("command is: set thr <n>");
 +
    }
 +
    else if (command.get(0).asString()=="set") {
 +
      if (command.get(1).asString()=="thr") {
 +
          thresholdValue = command.get(2).asInt(); // set parameter value
 +
          reply.addString("ok");
 +
      }
 +
    }
 +
    return true;
 +
}
 +
 +
However, for any of this to work, we have to set up a port in the first place.  We put the port declaration in the private data member part of <code>ProtoComponent</code> class
 +
 +
    string handlerPortName;
 +
    ...
 +
    Port handlerPort;                              // a port to handle interactive messages (also uses bottles)
 +
 +
and open it in the <code>configure()</code> method, viz.
 +
 +
    /*
 +
    * attach a port of the same name as the module (prefixed with a /) to the module
 +
    * so that messages received from the port are redirected to the respond method
 +
    */
 +
 +
    handlerPortName =  "/";
 +
    handlerPortName += getName();        // use getName() rather than a literal
 +
 
 +
    if (!handlerPort.open(handlerPortName.c_str())) {         
 +
      cout << getName() << ": Unable to open port " << handlerPortName << endl; 
 +
      return false;
 +
    }
 +
 +
    attach(handlerPort);                  // attach to port
 +
 +
Interrupt it in the <code>interrupt()</code> method, viz.
 +
 +
    handlerPort.interrupt();
 +
 +
Close it in the <code>close()</code> method, viz.
 +
 +
    handlerPort.close();
 +
 +
==== Remote Connection ====
 +
 +
Note that the <code>handlerport</code> can be used not only by other modules but also interactively by a user through the <code>yarp rpc</code> directive, viz.:
 +
 +
yarp rpc /protoComponent
 +
 +
This opens a connection from a terminal to the port and allows the user to then type in commands and receive replies from the <code>respond()</code> method.
 +
 +
=== An Example of how to Configure the Component ===
 +
 +
The following example summarizes how to handle all the configuration issues discussed above.  This is taken directly from the [[The protoComponent Example | <code>protoComponent</code> source code]].
 +
 +
/** @file protoComponent.h  Interface file for the example CINDY component */
 +
 +
#include <iostream>
 +
#include <string>
 +
 +
#include <yarp/sig/all.h>
 
  #include <yarp/os/all.h>
 
  #include <yarp/os/all.h>
 
  #include <yarp/os/RFModule.h>
 
  #include <yarp/os/RFModule.h>
 
  #include <yarp/os/Network.h>
 
  #include <yarp/os/Network.h>
 
  #include <yarp/os/Thread.h>
 
  #include <yarp/os/Thread.h>
#include <yarp/sig/all.h>
+
 
+
 
  using namespace std;
 
  using namespace std;
 
  using namespace yarp::os;  
 
  using namespace yarp::os;  
 
  using namespace yarp::sig;
 
  using namespace yarp::sig;
 +
 
 +
class ProtoComponentThread : public Thread {
 +
 +
private:
 +
 +
    /* class variables */
 +
 +
    bool              debug;
 +
    int                x, y;
 +
    PixelRgb          rgbPixel;
 +
    ImageOf<PixelRgb> *image;
 +
    int              *thresholdValue; 
 +
    VectorOf<int>    *thresholdVector;
 +
    int              numberOfForegroundPixels;
 +
 +
    /* thread parameters: they are pointers so that they refer to the original variables in protoComponent */
 +
 +
    BufferedPort<ImageOf<PixelRgb> > *imagePortIn;
 +
    BufferedPort<VectorOf<int> >    *thresholdPortIn;
 +
    BufferedPort<ImageOf<PixelRgb> > *imagePortOut;
 +
    BufferedPort<Bottle>            *statisticsPortOut;
 +
 +
  public:
 +
 
 +
    /* class methods */
 +
 
 +
    ProtoComponentThread(BufferedPort<ImageOf<PixelRgb> > *imageIn,
 +
                          BufferedPort<VectorOf<int> >    *thresholdIn,
 +
                          BufferedPort<ImageOf<PixelRgb> > *imageOut,
 +
                          BufferedPort<Bottle>            *statisticsOut,
 +
                          int *threshold );
 +
    bool threadInit();   
 +
    void threadRelease();
 +
    void run();
 +
};
 +
 +
 +
class ProtoComponent:public RFModule {
 
   
 
   
class MyModule:public RFModule
 
{
 
 
     /* module parameters */
 
     /* module parameters */
 
   
 
   
 
     string moduleName;
 
     string moduleName;
     string robotName;  
+
     string imageInputPortName;
     string robotPortName;
+
     string thresholdInputPortName;
     string inputPortName;
+
     string imageOutputPortName;
     string outputPortName;   
+
     string statisticsOutputPortName;   
 +
    string handlerPortName;
 
     string cameraConfigFilename;
 
     string cameraConfigFilename;
 
     float  fxLeft,  fyLeft;          // focal length
 
     float  fxLeft,  fyLeft;          // focal length
Line 285: Line 562:
 
     float  cxLeft,  cyLeft;          // coordinates of the principal point
 
     float  cxLeft,  cyLeft;          // coordinates of the principal point
 
     float  cxRight, cyRight;        // coordinates of the principal point
 
     float  cxRight, cyRight;        // coordinates of the principal point
     int thresholdValue;
+
     int   thresholdValue;
   
+
 
     /* class variables */
 
     /* class variables */
 
   
 
   
     BufferedPort<ImageOf<PixelRgb> > imageIn;     //example input port
+
     BufferedPort<ImageOf<PixelRgb> > imageIn;       // example image input port
     BufferedPort<ImageOf<PixelRgb> > imageOut;    //example output port
+
    BufferedPort<VectorOf<int> >    thresholdIn;  // example vector input port  
 +
     BufferedPort<ImageOf<PixelRgb> > imageOut;     // example image output port
 +
     BufferedPort<Bottle>            statisticsOut; // example bottle output port
 +
    Port handlerPort;                              // a port to handle interactive messages (also uses bottles)
 +
 +
    /* pointer to a new thread to be created and started in configure() and stopped in close() */
 +
 +
    ProtoComponentThread *protoComponentThread;
 
   
 
   
 
  public:
 
  public:
   
+
 
 
     bool configure(yarp::os::ResourceFinder &rf); // configure all the module parameters and return true if successful
 
     bool configure(yarp::os::ResourceFinder &rf); // configure all the module parameters and return true if successful
 
     bool interruptModule();                      // interrupt, e.g., the ports  
 
     bool interruptModule();                      // interrupt, e.g., the ports  
 
     bool close();                                // close and shut down the module
 
     bool close();                                // close and shut down the module
     bool respond(const Bottle& command, Bottle& reply)
+
     bool respond(const Bottle& command, Bottle& reply);
 
     double getPeriod();  
 
     double getPeriod();  
 
     bool updateModule();
 
     bool updateModule();
  };
+
  };  
+
 
+
  
 +
/* protoComponentConfiguration.cpp  Implementation file for the example CINDY component */
 +
 
 
  /*  
 
  /*  
   * Configure method. Receive a previously initialized
+
   * Configure method ... use it to do component coordination,  
  * resource finder object. Use it to configure your module.
+
   * i.e. to configure your component at runtime
  * If you are migrating from the old Module, this is the
+
   * equivalent of the "open" method.
+
 
   */
 
   */
 
   
 
   
  bool MyModule::configure(yarp::os::ResourceFinder &rf)
+
  bool ProtoComponent::configure(yarp::os::ResourceFinder &rf)
 
  {     
 
  {     
 
     /* Process all parameters from both command-line and .ini file */
 
     /* Process all parameters from both command-line and .ini file */
Line 318: Line 600:
 
   
 
   
 
     moduleName            = rf.check("name",  
 
     moduleName            = rf.check("name",  
                             Value("myModule"),  
+
                             Value("protoComponent"),  
 
                             "module name (string)").asString();
 
                             "module name (string)").asString();
 
   
 
   
Line 325: Line 607:
 
     * specifically the port names which are dependent on the module name
 
     * specifically the port names which are dependent on the module name
 
     */
 
     */
   
+
 
 
     setName(moduleName.c_str());
 
     setName(moduleName.c_str());
 
   
 
   
 
     /* now, get the rest of the parameters */
 
     /* now, get the rest of the parameters */
 
   
 
   
 +
    /* get the name of the input and output ports, automatically prefixing the module name by using getName() */
 
   
 
   
 +
    imageInputPortName    =      "/";
 +
    imageInputPortName  +=      getName(
 +
                                rf.check("imageInputPort",
 +
                                Value("/image:i"),
 +
                                "Input image port (string)").asString()
 +
                                );
 +
   
 +
    thresholdInputPortName =    "/";
 +
    thresholdInputPortName +=    getName(
 +
                                rf.check("thresholdInputPort",
 +
                                Value("/threshold:i"),
 +
                                "Threshold input port (string)").asString()
 +
                                );
 +
 +
    imageOutputPortName  =      "/";
 +
    imageOutputPortName  +=      getName(
 +
                                rf.check("imageOutputPort",
 +
                                Value("/image:o"),
 +
                                "Output image port (string)").asString()
 +
                                );
 +
 +
    statisticsOutputPortName  = "/";
 +
    statisticsOutputPortName  += getName(
 +
                                rf.check("statisticsOutputPort",
 +
                                Value("/statistics:o"),
 +
                                "Output image port (string)").asString()
 +
                                );
 +
 +
 +
    /* get the threshold value */
 +
 +
    thresholdValue        = rf.check("threshold",
 +
                            Value(8),
 +
                            "Key value (int)").asInt();
 +
 +
   
 
     /*  
 
     /*  
 
     * get the cameraConfig file and read the required parameter values cx, cy  
 
     * get the cameraConfig file and read the required parameter values cx, cy  
Line 337: Line 656:
 
   
 
   
 
     cameraConfigFilename  = rf.check("cameraConfig",  
 
     cameraConfigFilename  = rf.check("cameraConfig",  
                             Value("robotEyes.ini"),  
+
                             Value("cameras.ini"),  
 
                             "camera configuration filename (string)").asString();
 
                             "camera configuration filename (string)").asString();
 
   
 
   
Line 345: Line 664:
 
   
 
   
 
     if (cameraProperties.fromConfigFile(cameraConfigFilename.c_str()) == false) {
 
     if (cameraProperties.fromConfigFile(cameraConfigFilename.c_str()) == false) {
       cout << "myModule: unable to read camera configuration file" << cameraConfigFilename;
+
       cout << "protoComponent: unable to read camera configuration file" << cameraConfigFilename << endl;
 
       return 0;
 
       return 0;
 
     }
 
     }
Line 354: Line 673:
 
       cyRight = (float) cameraProperties.findGroup("CAMERA_CALIBRATION_RIGHT").check("cy", Value(120.0), "cy right").asDouble();
 
       cyRight = (float) cameraProperties.findGroup("CAMERA_CALIBRATION_RIGHT").check("cy", Value(120.0), "cy right").asDouble();
 
     }
 
     }
 
    /* get the name of the input and output ports, automatically prefixing the module name by using getName() */
 
 
    inputPortName        = "/";
 
    inputPortName        += getName(
 
                            rf.check("myInputPort",
 
                            Value("/image:i"),
 
                            "Input image port (string)").asString()
 
                            );
 
   
 
    outputPortName        = "/";
 
    outputPortName      += getName(
 
                            rf.check("myOutputPort",
 
                            Value("/image:o"),
 
                            "Output image port (string)").asString()
 
                            );
 
 
    /* get the threshold value */
 
 
    thresholdValue        = rf.check("threshold",
 
                            Value(8),
 
                            "Key value (int)").asInt();
 
 
   
 
   
 
   
 
   
Line 382: Line 679:
 
     /* open ports  */  
 
     /* open ports  */  
 
          
 
          
     if (!imageIn.open(inputPortName.c_str())) {
+
     if (!imageIn.open(imageInputPortName.c_str())) {
       cout << getName() << ": unable to open port " << inputPortName << endl;
+
       cout << getName() << ": unable to open port " << imageInputPortName << endl;
 
       return false;  // unable to open; let RFModule know so that it won't run
 
       return false;  // unable to open; let RFModule know so that it won't run
 
     }
 
     }
 
   
 
   
     if (!imageOut.open(outputPortName.c_str())) {
+
     if (!thresholdIn.open(thresholdInputPortName.c_str())) {
       cout << getName() << ": unable to open port " << outputPortName << endl;
+
       cout << getName() << ": unable to open port " << thresholdInputPortName << endl;
 
       return false;  // unable to open; let RFModule know so that it won't run
 
       return false;  // unable to open; let RFModule know so that it won't run
 
     }
 
     }
 
   
 
   
    return true ;  // let the RFModule know everything went well
 
                    // so that it will then run the module
 
}
 
 
int main(int argc, char * argv[])
 
{
 
    /* initialize yarp network */
 
 
   
 
   
     Network yarp;
+
     if (!imageOut.open(imageOutputPortName.c_str())) {
 +
      cout << getName() << ": unable to open port " << imageOutputPortName << endl;
 +
      return false;  // unable to open; let RFModule know so that it won't run
 +
    }
 
   
 
   
     /* create your module */
+
     if (!statisticsOut.open(statisticsOutputPortName.c_str())) {
 +
      cout << getName() << ": unable to open port " << statisticsOutputPortName << endl;
 +
      return false;  // unable to open; let RFModule know so that it won't run
 +
    }
 
   
 
   
    MyModule myModule;
 
 
   
 
   
     /* prepare and configure the resource finder */
+
     /*
 +
    * attach a port of the same name as the module (prefixed with a /) to the module
 +
    * so that messages received from the port are redirected to the respond method
 +
    */
 
   
 
   
     ResourceFinder rf;
+
     handlerPortName =  "/";
    rf.setVerbose(true);
+
     handlerPortName += getName();         // use getName() rather than a literal
    rf.setDefaultConfigFile("myModule.ini"); //overridden by --from parameter
+
     rf.setDefaultContext("myModule/conf");   //overridden by --context parameter
+
    rf.configure("DREAM_ROOT", argc, argv);
+
 
    
 
    
     /* run the module: runModule() calls configure first and, if successful, it then runs */
+
     if (!handlerPort.open(handlerPortName.c_str())) {         
 +
      cout << getName() << ": Unable to open port " << handlerPortName << endl; 
 +
      return false;
 +
    }
 
   
 
   
     myModule.runModule(rf);
+
     attach(handlerPort);                 // attach to port
 +
 
 +
    /* create the thread and pass pointers to the module parameters */
 
   
 
   
     return 0;
+
    protoComponentThread = new ProtoComponentThread(&imageIn, &thresholdIn, &imageOut, &statisticsOut, &thresholdValue);
 +
 +
    /* now start the thread to do the work */
 +
 +
    protoComponentThread->start(); // this calls threadInit() and it if returns true, it then calls run()
 +
 
 +
     return true ;     // let the RFModule know everything went well
 +
                      // so that it will then run the module
 
  }
 
  }
  
== Graceful Shut-down ==
+
/* protoComponentMain.cpp Application file for the example CINDY component */
 +
 
 +
#include "protoComponent.h"
 +
 
 +
int main(int argc, char * argv[])
 +
{
 +
  /* initialize yarp network */
 +
 
 +
  Network yarp;
 +
 
 +
  /* create your module */
 +
 
 +
  ProtoComponent protoComponent;
 +
 
 +
  /* prepare and configure the resource finder */
 +
 
 +
  ResourceFinder rf;
 +
  rf.setVerbose(true);
 +
  rf.setDefaultConfigFile("protoComponent.ini");          // can be overridden by --from parameter
 +
  rf.setDefaultContext("protoComponent/configuration");  // can be overridden by --context parameter
 +
  rf.configure("CINDY_ROOT", argc, argv);                // environment variable with root of configuration path
 +
 
 +
  /* run the module: runModule() calls configure first and, if successful, it then runs */
 +
 
 +
  protoComponent.runModule(rf);
 +
 
 +
  return 0;
 +
}
  
 +
=== Doing Some Work: Instantiating and starting the <code>protoComponentThread</code> ===
  
To achieve clean shutdown, two methods <code>yarp::os::RFModule::interruptModule()</code> and <code>yarp::os::RFModule::close()</code> should be overridden. The <code>interruptModule()</code> method will be called when it is desired that <code>updateModule()</code> finish up. When it has indeed finished, <code>close()</code> will be called. For example:
+
Once the configuration is done (in <code>protoComponentConfiguration.cpp</code>), the derived module then instantiates a <code>Thread</code>  (or  <code>RateThread</code>) object and launches it (again, this is done in <code>protoComponentConfiguration.cpp</code>), passing to it as arguments all the relevant resources, e.g. port names and parameter values, located by the resource finder.
 +
 
 +
In the example above, this we done as follows.
 +
 
 +
    /* create the thread and pass pointers to the module parameters */
 +
 +
    protoComponentThread = new ProtoComponentThread(&imageIn, &thresholdIn, &imageOut, &statisticsOut, &thresholdValue);
 +
 +
    /* now start the thread to do the work */
 +
 +
    protoComponentThread->start(); // this calls threadInit() and it if returns true, it then calls run()
 +
 
 +
=== Graceful Shut-down ===
 +
 
 +
To achieve clean shutdown, two <code>RFModule</code> methods, <code>yarp::os::RFModule::interruptModule()</code> and <code>yarp::os::RFModule::close()</code>, should be overridden.  
 +
 
 +
The <code>interruptModule()</code> method will be called when it is desired that <code>updateModule()</code> finish up. When it has indeed finished, <code>close()</code> will be called.
 +
 
 +
The <code>interruptModule()</code> method should first call the <code>stop()</code> method for the thread (e.g.  <code>protoComponentThread->stop();</code>) and then call the <code>interrupt</code> method for each of the ports that it opened in the <code>configure()</code> method. For example:
 
      
 
      
  bool MyModule::interruptModule()
+
  bool ProtoComponent::interruptModule()
 
  {
 
  {
 +
    protoComponentThread->stop();
 +
 
     imageIn.interrupt();
 
     imageIn.interrupt();
 +
    thresholdIn.interrupt();
 
     imageOut.interrupt();
 
     imageOut.interrupt();
 +
    handlerPort.interrupt();
 +
 
     return true;
 
     return true;
 
  }
 
  }
 
+
  bool MyModule::close()
+
  bool ProtoComponent::close()
  {
+
  {  
 
     imageIn.close();
 
     imageIn.close();
 +
    thresholdIn.close();
 
     imageOut.close();
 
     imageOut.close();
 +
    handlerPort.close();
 +
 
     return true;
 
     return true;
  }
+
  }  
  
 +
The order in which you do this is very important: first <code>stop()</code> the thread, then <code>interrupt()</code> the ports, then <code>close()</code> the ports. Getting this out of sequence causes problems when shutting down a component and it will often hang, requiring you to kill the process.
  
 
For <code>yarp::os::RFModule</code>, the method <code>yarp::os::RFModule::updateModule()</code> will be called from the main control thread until it returns false. After that a clean shutdown will be initiated. The period with which it is called is determined by the method <code>yarp::os::RFModule::getPeriod()</code>. Neither method need necessarily be overridden.  The default methods provide the required functionality.   
 
For <code>yarp::os::RFModule</code>, the method <code>yarp::os::RFModule::updateModule()</code> will be called from the main control thread until it returns false. After that a clean shutdown will be initiated. The period with which it is called is determined by the method <code>yarp::os::RFModule::getPeriod()</code>. Neither method need necessarily be overridden.  The default methods provide the required functionality.   
Line 445: Line 807:
 
  /* Called periodically every getPeriod() seconds */
 
  /* Called periodically every getPeriod() seconds */
 
   
 
   
  bool MyModule::updateModule()
+
  bool ProtoComponent::updateModule()
 
  {
 
  {
 
     return true;
 
     return true;
 
  }
 
  }
 
+
  double MyModule::getPeriod()
+
  double ProtoComponent::getPeriod()
 
  {
 
  {
     /* module periodicity (seconds), called implicitly by myModule */
+
     /* module periodicity (seconds), called implicitly by protoComponent */
 
      
 
      
 
     return 0.1;
 
     return 0.1;
 
  }
 
  }
 
  
 
Note that the <code>updateModule()</code> method is not meant to run code that that implements the algorithm encapsulated in the module.  Instead <code>updateModule()</code> is meant to be used as a periodic mechanism to check in on the operation of the thread that implements  the module (e.g. gather interim statistics, change parameter settings, etc.).  The <code>updateModule()</code> is called periodically by the RFModule object, with the period being determined by the <code>getPeriod()</code> method.  Both <code>updateModule()</code> and <code>getPeriod()</code> can be overridden in your implementation of <code>myModule</code>.
 
Note that the <code>updateModule()</code> method is not meant to run code that that implements the algorithm encapsulated in the module.  Instead <code>updateModule()</code> is meant to be used as a periodic mechanism to check in on the operation of the thread that implements  the module (e.g. gather interim statistics, change parameter settings, etc.).  The <code>updateModule()</code> is called periodically by the RFModule object, with the period being determined by the <code>getPeriod()</code> method.  Both <code>updateModule()</code> and <code>getPeriod()</code> can be overridden in your implementation of <code>myModule</code>.
  
== Thread-based Implementation ==
+
== Component  Computation and Communication: the <code>Thread</code> and  <code>RateThread</code> Classes  ==
 +
 
 +
Here we finally explain how to get the component to do some work: the functionality associated with computation and communication. This is defined in the  <code>protoComponentComputation.cpp</code> file.  This functionality revolves around the  <code>Thread</code>  and  <code>RateThread</code> classes: how to access the parameters passed to it from the derived <code>RFModule</code> object, how to perform some useful work.
  
 
=== Using Threads to Implement Your Algorithm ===
 
=== Using Threads to Implement Your Algorithm ===
  
For the module to actually do anything, it should start or stop threads using the YARP [http://wiki.icub.org/yarpdoc/d2/d2d/classyarp_1_1os_1_1Thread.html Thread] and [http://wiki.icub.org/yarpdoc/d9/d9c/classyarp_1_1os_1_1RateThread.html RateThread] classes. Typically, these threads are started and stopped in the <code>configure</code> and <code>close</code> methods of the RFModule class. If you are writing a control loop or an algorithm that requires precise scheduling we strongly advise that you use the [http://wiki.icub.org/yarpdoc/d9/d9c/classyarp_1_1os_1_1RateThread.html RateThread] class.
+
For the module to actually do anything, it should start or stop threads using the YARP [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1Thread.html Thread] and [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1RateThread.html RateThread] classes. Typically, these threads are started and stopped in the <code>configure</code> and <code>close</code> methods of the RFModule class. If you are writing a control loop or an algorithm that requires precise scheduling your should use the [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1RateThread.html RateThread] class.
  
 +
Just as the starting point in writing a component for the CINDY repository is to develop a sub-class of the [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1RFModule.html  yarp::os::RFModule] class, '''the starting point for implementing the algorithm within that component is to develop a sub-class of either [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1Thread.html Thread] or [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1RateThread.html RateThread]'''.
  
Just as the starting point in writing a module for the DREAM repository is to develop a sub-class of the [http://wiki.icub.org/yarpdoc/d9/d26/classyarp_1_1os_1_1RFModule.html yarp::os::RFModule] class, '''the starting point for implementing the algorithm within that module is to develop a sub-class of either [http://wiki.icub.org/yarpdoc/d2/d2d/classyarp_1_1os_1_1Thread.html Thread] or [http://wiki.icub.org/yarpdoc/d9/d9c/classyarp_1_1os_1_1RateThread.html RateThread]'''.  
+
In the following, we will explain how to do it with [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1Thread.html Thread]; it's straightforward to extend this to [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1RateThread.html RateThread]: effectively, you provide an argument with the <code>RateThread</code> instantiation specifying the period with which the thread should be spawned; the thread just runs once so that you don't have to check <code>isStopping()</code> to see if the thread should end as in the [http://wiki.icub.org/yarpdoc/classyarp_1_1os_1_1Thread.html Thread] example below.
  
 +
'''Perhaps one of the best ways of thinking about this is to view it as a two levels of encapsulation, one with <code>RFModule</code>, and another with <code>Thread</code>; the former deals with the configuration of the module and the latter dealing with the execution of the algorithm.'''  The only tricky part is that somehow these two objects have to communicate with one another. 
  
In the following, we will explain how to do it with [http://wiki.icub.org/yarpdoc/d2/d2d/classyarp_1_1os_1_1Thread.html Thread]; it's straightforward to extend this to [http://wiki.icub.org/yarpdoc/d9/d9c/classyarp_1_1os_1_1RateThread.html RateThread] (effectively, you provide an argument with the <code>RateThread</code> instantiation specifying the period with which the thread should be spawned, the thread just runs once so that you don't have to check <code>isStopping()</code> to see if the thread should end).
+
You need to know three things (two of which  we can covered already):
 
+
 
+
Perhaps one of the best ways of thinking about this is to view it as a two levels of encapsulation, one with <code>RFModule</code>, and another with <code>Thread</code>; the former deals with the configuration of the module and the latter dealing with the execution of the algorithm.  The only tricky part is that somehow these two objects have to communicate with one another. 
+
 
+
 
+
You need to know three things:
+
 
+
  
 
# The thread is instantiated and started in the <code>configure()</code> method.   
 
# The thread is instantiated and started in the <code>configure()</code> method.   
Line 483: Line 841:
 
# When the thread is instantiated, you pass the module parameters to it as a set of arguments (for the constructor).
 
# When the thread is instantiated, you pass the module parameters to it as a set of arguments (for the constructor).
  
 +
Let's begin with the definition of a thread <code>ProtoComponentThread</code> (capital P because we are going to create a sub-class) and then turn our attention to how it is used by <code>protoComponent</code>.
  
Let's begin with the definition of a thread <code>MyThread</code> (capital M because we are going to create a sub-class) and then turn our attention to how it is used by <code>MyModule</code>.
+
=== An example of how to use the <code>Thread</code> class ===
 
+
=== An Example of how to use the <code>Thread</code> Class ===
+
  
 
First, we define a sub-class, or derived class, of the <code>yarp::os::Thread</code> class.  The algorithm's variables - ''and specifically the thread's parameters and ports'' - go in the private data members part and you need to override four methods:
 
First, we define a sub-class, or derived class, of the <code>yarp::os::Thread</code> class.  The algorithm's variables - ''and specifically the thread's parameters and ports'' - go in the private data members part and you need to override four methods:
  
 
+
# <code>ProtoComponentThread::ProtoComponentThread();          // the constructor</code>
# <code>MyThread::MyThread();          // the constructor</code>
+
# <code>bool threadInit();                                   // initialize variables and return true if successful</code>
# <code>bool threadInit();             // initialize variables and return true if successful</code>
+
# <code>void run();                                           // do the work</code>
# <code>void run();                     // do the work</code>
+
# <code>void threadRelease();                                 // close and shut down the thread</code>
# <code>void threadRelease();           // close and shut down the thread</code>
+
 
+
  
 
There are a number of important points to note.
 
There are a number of important points to note.
  
 
+
First, the variables in the <code>ProtoComponentThread</code> class which represent the thread's parameters and port should be pointer types and the constructor parameters should initialize them.  In turn, the arguments of the <code>protoComponentThread</code> object instantiation in the <code>configure()</code> should be the addresses of (pointers to) the module parameters and ports in the <code>protoComponentThread</code> object.  In this way, the thread's parameter and port variables are just references to the original module parameters and ports that were initialized in the <code>configure</code> method of the <code>protoComponent</code> object.
First, the variables in the <code>myThread</code> class which represent the thread's parameters and port should be pointer types and the constructor parameters should initialize them.  In turn, the arguments of the <code>myThread</code> object instantiation in the <code>configure()</code> should be the addresses of (pointers to) the module parameters and ports in the <code>myModule</code> object.  In this way, the thread's parameter and port variables are just references to the original module parameters and ports that were initialized in the <code>configure</code> method of the <code>myModule</code> object.
+
 
+
  
 
Second, <code>threadInit()</code> returns <code>true</code> if the initialization was successful, otherwise it should return <code>false</code>.  This is significant because if it returns <code>false</code> the thread will not subsequently be run.
 
Second, <code>threadInit()</code> returns <code>true</code> if the initialization was successful, otherwise it should return <code>false</code>.  This is significant because if it returns <code>false</code> the thread will not subsequently be run.
  
 +
Third, '''the <code>run()</code> method is where the algorithm is implemented.''' Typically, it will run continuously until some stopping condition is met.  This stopping condition should include the return value of a call to the <code>yarp::os::Thread::isStopping()</code> method which flags whether or not the thread is to terminate.  In turn, the value of  <code>yarp::os::Thread::isStopping()</code> is determined by the  <code>yarp::os::Thread::stop()</code> method which, as we saw already, is called in <code>protoComponent.close()</code>.
  
Third, the <code>run()</code> method is where the algorithm is implemented. Typically, it will run continuously until some stopping condition is met.  This stopping condition should include the return value of a call to the <code>yarp::os::Thread::isStopping()</code> method which flags whether or not the thread is to terminate.  In turn, the value of  <code>yarp::os::Thread::isStopping()</code> is determined by the  <code>yarp::os::Thread::stop()</code> method which, as we will see, is called in <code>myModule.close()</code>
+
The following is an example declaration and definition of the <code>ProtoComponentThread</code> class taken from <code>protoComponent.h</code>
 
+
 
+
The following is an example declaration and definition of the <code>MyThread</code> class.
+
 
+
  
 +
/** @file protoComponent.h  Interface file for the example CINDY component */
 +
 
 
  #include <yarp/os/Thread.h>
 
  #include <yarp/os/Thread.h>
+
 
 
  using namespace std;
 
  using namespace std;
  using namespace yarp::os;
+
  using namespace yarp::os;
 +
using namespace yarp::sig;
 
    
 
    
  class MyThread : public Thread
+
  class ProtoComponentThread : public Thread {
  {
+
   
 
  private:
 
  private:
 
   
 
   
 
     /* class variables */
 
     /* class variables */
 
   
 
   
     int     x, y;
+
    bool              debug;
     PixelRgb rgbPixel;
+
     int               x, y;
 +
     PixelRgb           rgbPixel;
 
     ImageOf<PixelRgb> *image;
 
     ImageOf<PixelRgb> *image;
     
+
    int              *thresholdValue; 
     /* thread parameters: they are pointers so that they refer to the original variables in myModule */
+
     VectorOf<int>    *thresholdVector;
 +
    int              numberOfForegroundPixels;
 
   
 
   
     BufferedPort<ImageOf<PixelRgb>> *imagePortIn;
+
     /* thread parameters: they are pointers so that they refer to the original variables in protoComponent */
    BufferedPort<ImageOf<PixelRgb>> *imagePortOut; 
+
    int *thresholdValue;   
+
+
public:
+
 
   
 
   
     /* class methods */
+
     BufferedPort<ImageOf<PixelRgb> > *imagePortIn;
+
    BufferedPort<VectorOf<int> >    *thresholdPortIn;
    MyThread(BufferedPort<ImageOf<PixelRgb>> *imageIn, BufferedPort<ImageOf<PixelRgb>> *imageOut, int *threshold );
+
    BufferedPort<ImageOf<PixelRgb> > *imagePortOut;
    bool threadInit();     
+
    BufferedPort<Bottle>            *statisticsPortOut;
    void threadRelease();
+
   
    void run();  
+
  public:
 +
 
 +
    /* class methods */
 +
 
 +
    ProtoComponentThread(BufferedPort<ImageOf<PixelRgb> > *imageIn,  
 +
                          BufferedPort<VectorOf<int> >    *thresholdIn,
 +
                          BufferedPort<ImageOf<PixelRgb> > *imageOut,
 +
                          BufferedPort<Bottle>            *statisticsOut,
 +
                          int *threshold );
 +
    bool threadInit();     
 +
    void threadRelease();
 +
    void run();  
 
  };
 
  };
  
  MyThread::MyThread(BufferedPort<ImageOf<PixelRgb>> *imageIn, BufferedPort<ImageOf<PixelRgb>> *imageOut, int *threshold)
+
  /* protoComponentComputation.cpp Implementation file for the computation and communication aspects of protoComponent */
 +
 +
ProtoComponentThread::ProtoComponentThread(BufferedPort<ImageOf<PixelRgb> > *imageIn,  
 +
                                            BufferedPort<VectorOf<int> >    *thresholdIn,
 +
                                            BufferedPort<ImageOf<PixelRgb> > *imageOut,
 +
                                            BufferedPort<Bottle>            *statisticsOut,
 +
                                            int *threshold)
 
  {
 
  {
     imagePortIn   = imageIn;
+
     imagePortIn       = imageIn;
     imagePortOut   = imageOut;
+
     thresholdPortIn   = thresholdIn;
     thresholdValue = threshold;
+
    imagePortOut      = imageOut;
 +
    statisticsPortOut = statisticsOut;
 +
     thresholdValue   = threshold;
 
  }
 
  }
 
   
 
   
  bool MyThread::threadInit()  
+
  bool ProtoComponentThread::threadInit()  
 
  {
 
  {
 
     /* initialize variables and create data-structures if needed */
 
     /* initialize variables and create data-structures if needed */
 +
 +
    debug = false;
 
   
 
   
 
     return true;
 
     return true;
  }
+
  }  
 
   
 
   
  void MyThread::run(){
+
  void ProtoComponentThread::run(){
 
   
 
   
 
     /*  
 
     /*  
Line 565: Line 937:
 
      
 
      
 
     unsigned char value;
 
     unsigned char value;
 +
    double start;
 +
 
 +
    start = yarp::os::Time::now(); // start time
 
   
 
   
 
     while (isStopping() != true) { // the thread continues to run until isStopping() returns true
 
     while (isStopping() != true) { // the thread continues to run until isStopping() returns true
 
+
 
       cout << "myThread: threshold value is " << *thresholdValue << endl;
+
       if (debug)
 +
          cout << "protoComponentThread: threshold value is " << *thresholdValue << endl;
 
        
 
        
 +
      /* read image ... block until image is received */
 +
 
       do {
 
       do {
 
           image = imagePortIn->read(true);
 
           image = imagePortIn->read(true);
       } while (image == NULL);
+
       } while ((image == NULL) && (isStopping() != true));  // exit loop if shutting down;
 
        
 
        
 +
      if (isStopping()) break; // abort this loop to avoid make sure we don't continue and possibly use NULL images
 +
 +
 +
      /* read threshold ... block if threshold is not received */
 +
      /*
 +
      do {
 +
          thresholdVector = thresholdPortIn->read(false);
 +
      } while ((thresholdVector == NULL) && (isStopping() != true));  // exit loop if shutting down;
 +
      */
 +
 
 +
      /* read threshold ... do not block if threshold is not received */
 +
 +
      thresholdVector = thresholdPortIn->read(false);
 +
   
 +
      if (thresholdVector != NULL) {
 +
            *thresholdValue = (int) (*thresholdVector)[0];
 +
      }
 +
 +
 +
      if (debug)
 +
          cout << "protoComponentThread: threshold value is " << *thresholdValue << endl;
 +
     
 +
 +
      /* write out the binary image */
 +
 
       ImageOf<PixelRgb> &binary_image = imagePortOut->prepare();
 
       ImageOf<PixelRgb> &binary_image = imagePortOut->prepare();
 
       binary_image.resize(image->width(),image->height());
 
       binary_image.resize(image->width(),image->height());
 +
 +
      numberOfForegroundPixels = 0;
 
   
 
   
 
       for (x=0; x<image->width(); x++) {
 
       for (x=0; x<image->width(); x++) {
Line 584: Line 989:
 
               if (((rgbPixel.r + rgbPixel.g + rgbPixel.b)/3) > *thresholdValue) {
 
               if (((rgbPixel.r + rgbPixel.g + rgbPixel.b)/3) > *thresholdValue) {
 
                 value = (unsigned char) 255;
 
                 value = (unsigned char) 255;
 +
                numberOfForegroundPixels++;
 
               }
 
               }
 
               else {
 
               else {
Line 595: Line 1,001:
 
               binary_image(x,y) = rgbPixel;
 
               binary_image(x,y) = rgbPixel;
 
           }
 
           }
         }  
+
         }
+
       
 
         imagePortOut->write();
 
         imagePortOut->write();
 +
 +
        /* write out the image statistics */
 +
 +
        Bottle &statisticsMessage = statisticsPortOut->prepare();
 +
 +
        statisticsMessage.clear();
 +
 +
        statisticsMessage.addInt((int)(yarp::os::Time::now()-start));
 +
        statisticsMessage.addString("seconds elapsed");
 +
        statisticsMessage.addString(" - foreground pixel count is");
 +
        statisticsMessage.addInt(numberOfForegroundPixels);
 +
        statisticsPortOut->write();
 
     }
 
     }
 
  }
 
  }
 
   
 
   
  void MyThread::threadRelease()  
+
  void ProtoComponentThread::threadRelease()  
 
  {
 
  {
 
     /* for example, delete dynamically created data-structures */
 
     /* for example, delete dynamically created data-structures */
 
  }
 
  }
  
=== Creating, Starting, and Stopping the Thread ===
+
==   GUI Component Computation and Communication: the <code>FLTK</code> and  <code>guiUtilities</code> Libraries  ==
  
As we said already, the thread is instantiated and started in the <code>configure()</code> method in <code>myModule</code>, the thread is stopped in the <code>close()</code> method, and when the thread is instantiated, you pass the pointers to the module parameters to it as a set of arguments.  First, however, we add a new variable to the <code>MyModule</code> class.
+
This section explains how you can write your own graphic user interface (GUI).  We will use the specific example of a GUI for the <code>protoComponent</code> component.  This will be implemented as a separate stand-along component <code>protoComponentGUI</code>.
  
  /* pointer to a new thread to be created and started in configure() and stopped in close() */
+
The functionality associated with configuration and coordination, i.e. with the <code>protoComponentGUIConfiguration.cpp</code> and <code>protoComponentGUI.h</code> files, is essentially the same as for the <code>protoComponent</code> example so we will skip over that part.  For reference, you can see the complete source code in [[The protoComponentGUI Example]].
+
MyThread *myThread;
+
  
 +
Here we address the functionality associated with computation and communication, i.e. with the  <code> protoComponentGUIComputation.cpp </code> and  <code>protoComponent.h </code> files (also included in  [[The protoComponentGUI Example]]).  As with <code>protoComponent</code>, the functionality revolves around the  <code>Thread</code>  and  <code>RateThread</code> classes but the difference here is that the <code>ProtoComponentGUIThread::run()</code> now contains code to implement the GUI using the ''FLTK'' and  ''guiUtilities'' libraries.  That is the essential difference.
  
The following code would then go in the <code>configure()</code>  method.
+
First, we look at the definition of the <code>ProtoComponentGUIThread</code>.  The only thing worthy of note here is the use of the inclusion of the <code>guiUtilities.h</code> file to allow us use the ''guiUtilities'' library.  This library, which is included in the CINDY release software repository, provide a number of general-purpose classes and methods to lighten the burden of writing a GUI.  In particular, here we see the definition of the two images  <code>DVimage  *rgbDVImage;</code> and <code>DVimage *binaryDVImage;</code>. The <code>DVimage</code> is one of the utility classes in the ''guiUtilities'' library.  Other classes, which we will see later, include the <code>DVdisplay</code> class with is a specially-design GUI widget that allows the display of <code>DVimage</code> image objects.
  
 
+
  /** @file protoComponentGUI.h  Interface file for the example CINDY component */
  /* create the thread and pass pointers to the module parameters */
+
 
   
 
   
  myThread = new MyThread(&imageIn, &imageOut, &thresholdValue);
+
  #include <iostream>
 +
#include <string>
 
   
 
   
  /* now start the thread to do the work */
+
  #include <yarp/sig/all.h>
 +
#include <yarp/os/all.h>
 +
#include <yarp/os/RFModule.h>
 +
#include <yarp/os/Network.h>
 +
#include <yarp/os/Thread.h>
 +
 
 +
#include "guiUtilities.h"
 
   
 
   
  myThread->start(); // this calls threadInit() and it if returns true, it then calls run()
+
  using namespace std;
 
+
using namespace yarp::os;
 
+
using namespace yarp::sig;
The following code would go in the <code>close()</code> method.
+
 
 
+
  #define STRINGLENGTH 132 // used to define a string when post-processing the bottle messages
  /* stop the thread */
+
 
   
 
   
  myThread->stop();
+
  class ProtoComponentGUIThread : public Thread {
 +
 +
private:
 +
 +
  /* class variables */
 +
 +
    bool              debug;
 +
    int              x, y;
 +
    PixelRgb          rgbPixel;
 +
    int              *thresholdValue; 
 +
    nt              numberOfForegroundPixels;
 +
    int              rgb_width;
 +
    int              rgb_height;
 +
    int              rgb_depth;
 +
    int              binary_width;
 +
    int              binary_height;
 +
    int              binary_depth;
 +
    unsigned char    pixel_value;
 +
    float            float_pixel_value;
 +
    double            thresholdValueDouble;
 +
    string            logoFilenameValue;
 +
    int              temp;
 +
 
 +
    ImageOf<PixelRgb> *rgbYARPImage;
 +
    ImageOf<PixelRgb> *binaryYARPImage;
 +
    DVimage          *rgbDVImage;
 +
    DVimage          *binaryDVImage;
 +
    Bottle            *statisticsMessage;
 +
 +
    /* thread parameters: they are pointers so that they refer to the original variables in protoComponentGUI */
 +
 +
    BufferedPort<ImageOf<PixelRgb> > *colourImagePortIn;
 +
    BufferedPort<ImageOf<PixelRgb> > *binaryImagePortIn;
 +
    BufferedPort<Bottle>            *statisticsPortIn;
 +
    BufferedPort<VectorOf<int> >    *thresholdPortOut;
 +
 +
public:
 +
 +
    /* class methods */
 +
 +
    ProtoComponentGUIThread(BufferedPort<ImageOf<PixelRgb> > *colourImageIn,
 +
                            BufferedPort<ImageOf<PixelRgb> > *binaryImageIn,
 +
                            BufferedPort<Bottle>            *statisticsIn,
 +
                            BufferedPort<VectorOf<int> >    *thresholdOut,
 +
                            int *threshold,
 +
                            string logoFilename);
 +
    bool threadInit();   
 +
    void threadRelease();
 +
    void run();
 +
};
  
== Run-time Interaction ==
+
Note that the thread parameter list contains a filename.  This is the name of the file that contain the CINDY logo.  We pass it as a parameter from the <code>RFModule::configure()</code> so that we can user the resource finder to locate the file and its path.
  
=== The <code>respond()</code> Method ===
 
Often, it is very useful for a user or another module to send commands to control the behaviour of the module, e.g. interactively changing parameter values. The [http://wiki.icub.org/iCub/dox/html/group__icub__controlGaze2.html controlGaze2] module is a good example of this type of usage (see also [[VVV09_Control_Gazers_Group]]).
 
  
 +
Next, we look at the definition of the GUI itself in the <code>run()</code> method. For convenience, we will only show code snippets; refer to  [[The protoComponentGUI Example]] for the complete source code listing.
  
We accomplish this functionality for the <code>yarp::os::RFModule</code> by overridding the <code>yarp::os::RFModule::respond()</code> method which can then be configured to receive messages from either a port (typically named <code>/myModule</code>) or the terminal. This is effected by the <code>yarp::os::RFModule::attach(port)</code> and <code>yarp::os::RFModule::attachTerminal()</code> methods, respectively. Attaching both the port and the terminal means that commands from both sources are then handled in the same way.
+
The first thing to notice is the instantiation of a number of objects from   ''FLTK''  classes <code>Fl_Group</code>, <code>Fl_Box</code>and <code>Fl_PNG_Image</code>. These define a group of widgets, a variety of individual widget, and an image with the CINDY logo.
  
=== An Example of how to change module parameters at run-time===
+
/* protoComponentGUIComputation.cpp  Implementation file for the example CINDY component */
 +
 +
void ProtoComponentGUIThread::run(){
 +
 +
    Fl_Group *start_protoComponent_GUI;
 +
    Fl_Box *box1, *box2, *heading;
 +
    Fl_PNG_Image *logo=new Fl_PNG_Image(logoFilenameValue.c_str());
 +
 
 +
The next thing is the long list of variables that determine the presentation of the GUI.  These are then initialized in as subsequent section.  This may look tedious but it means that it is very easy to re-design the layout of the GUI. 
  
In the following example, we handle three commands:
+
    int i, j;
 +
    char modifiedString[STRINGLENGTH];
 +
 +
    /* variable that determine the presentation of the GUI */
 +
 +
    int control_panel_x, control_panel_y;
 +
    int control_panel_width, control_panel_height;
 +
    int heading_x, heading_y, heading_width, heading_height;
 +
    int display_width, display_height;
 +
    int display_x1, display_x2, display_y;
 +
    int display_spacing;
 +
    int display_offset_x, display_offset_y;
 +
    int control_offset_x, control_offset_y;
 +
    int button_size_x, button_size_y, button_spacing_y;
 +
    int input_size_x, input_size_y;
 +
    int title_height;
 +
    int threshold_x, threshold_y;
 +
    int threshold_size_x, threshold_size_y;
 +
    int section_spacing_y;
 +
    int window_width, window_height, border_width, border_height;
 +
    int text_output_width,text_output_height;
 +
    int text_output_x,  text_output_y;
 +
 +
    /* intialize the presentation settings */
 +
 +
    window_width  = GetSystemMetrics(SM_CXFULLSCREEN);      // this is the area available for the window on the screen
 +
    window_height = GetSystemMetrics(SM_CYFULLSCREEN);
 +
 +
    border_width  = GetSystemMetrics(SM_CXSIZEFRAME); 
 +
    border_height = GetSystemMetrics(SM_CYSIZEFRAME);
 +
 +
    display_width  = DISPLAY_WIDTH; 
 +
    display_height = DISPLAY_HEIGHT;
 +
    display_spacing = 25;
 +
 +
    heading_x = (window_width - display_width*2 - display_spacing)/2;
 +
    heading_y = MENUBAR_HEIGHT;
 +
    heading_width = display_width*2 + display_spacing;      // centre over displays
 +
    heading_height = HEADING_HEIGHT*2;                      // logo and caption
 +
 +
    display_offset_x = heading_x ;
 +
    display_offset_y = heading_y + heading_height;
 +
    display_x1 = display_offset_x;
 +
    display_x2 = display_x1 + display_spacing + display_width  ;
 +
    display_y  = display_offset_y;
 +
 
 +
    title_height = 12;
 +
 +
    button_size_x = 130;
 +
    button_size_y = 20;
 +
    button_spacing_y = 5;
 +
 +
    input_size_x = button_size_x;
 +
    input_size_y = button_size_y;
 +
 
 +
    control_offset_x = 20;
 +
    control_offset_y = 0;
 +
 +
    control_panel_width  = display_width * 1;
 +
    control_panel_height = display_height / 2; // alternative to match the panel height to the number of widgets:  
 +
                                              // control_panel_height = title_height + 1*(5 + button_size_y) + title_height;
 +
    control_panel_x = display_x2;
 +
    control_panel_y = display_y + display_height + display_spacing;
 +
 +
    section_spacing_y = 8;
 +
 +
    threshold_size_x = control_panel_width - 2 * control_offset_x;
 +
    threshold_size_y = input_size_y;
 +
    threshold_x = control_panel_x + control_offset_x;
 +
    threshold_y = control_panel_y + control_offset_x + 0 * (button_size_y + button_spacing_y); // 0 because threshold is the first widget in the control panel
 +
                                                                                              // increase by 1 for every extra widget added
 +
    text_output_width  = display_width;
 +
    text_output_height = display_height / 2;
 +
    text_output_x = display_offset_x;
 +
    text_output_y = display_offset_y + display_height + display_spacing;
 +
 
 +
With that done, we can then define a group with all the GUI widgets and add the widgets to this group, one by one.
  
* help
+
    /* define a group with all the GUI widgets */
* quit
+
* set
+
    start_protoComponent_GUI = new Fl_Group(0,MENUBAR_HEIGHT,window_width,window_height-MENUBAR_HEIGHT,"");
** set thr <n>  ... set the threshold
+
:(where <n> is an integer number)
+
    start_protoComponent_GUI->begin(); 
 +
 +
      /*  ... note: we don't declare heading because it is declared in the guiUtilities library  */
 +
 +
      heading = new Fl_Box(heading_x, heading_y,
 +
                            heading_width,heading_height,"The protoComponentGUI Example" );
 +
 +
      heading->align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER |  FL_ALIGN_IMAGE_OVER_TEXT);
 +
      heading->labelsize(20);
 +
      heading->labelcolor(FL_BLACK); 
 +
      heading->labelfont(FL_HELVETICA_BOLD);
 +
      heading->box(FL_NO_BOX);
 +
      heading->image(logo);
 +
 
 +
      /* boxes to frame images ... note: we don't declare box1 or box2 because they are declared in the guiUtilities library  */
 +
 
 +
      box1 = new Fl_Box(display_x1-BORDER,display_y-BORDER,
 +
                        display_width+2*BORDER,display_height+2*BORDER,"" );
 +
      box1->box(FL_DOWN_BOX);
 +
      box1->align(FL_ALIGN_BOTTOM | FL_ALIGN_CENTER);
 +
      box1->labelsize(12);
 +
    
 +
      box2 = new Fl_Box(display_x2-BORDER,display_y-BORDER,
 +
                        display_width+2*BORDER,display_height+2*BORDER,"" );
 +
      box2->box(FL_DOWN_BOX);
 +
      box2->align(FL_ALIGN_BOTTOM | FL_ALIGN_CENTER);
 +
      box2->labelsize(12);
 +
 
 +
      /* image display ... note: we don't declare display1 or display2 because they declared in the guiUtilities library  */
 +
     
 +
      display1 = new DVdisplay(display_x1, display_y,
 +
                            display_width,display_height);
 +
 +
      display2 = new DVdisplay(display_x2, display_y,
 +
                            display_width,display_height);
 +
 +
      /* box to frame controls */
 +
 +
      Fl_Box *control_panel;
 +
      control_panel = new Fl_Box(control_panel_x, control_panel_y, control_panel_width, control_panel_height,"" );
 +
      control_panel->align(FL_ALIGN_TOP | FL_ALIGN_CENTER | FL_ALIGN_INSIDE);
 +
      control_panel->labelsize(12);
 +
      control_panel->labelfont(FL_HELVETICA_BOLD);
 +
      control_panel->box(FL_PLASTIC_DOWN_BOX);
 +
 +
      /* threshold slider */
 +
 +
      Fl_Value_Slider *threshold;
 +
      threshold = new Fl_Value_Slider(threshold_x, threshold_y, threshold_size_x, threshold_size_y,"Binary Threshold Value");
 +
      threshold->type(FL_HOR_NICE_SLIDER);
 +
      threshold->textsize(11);
 +
      threshold->callback(valuator_cb, &thresholdValueDouble); // NB valuator_cb() is a general-purpose callback defined in guiUtilities.h
 +
      threshold->labelsize(12);                                // other general-purpose callbacks are defined there too, e.g. radio buttons
 +
      threshold->labelfont(FL_HELVETICA_BOLD);                // some widgets may require you to write your own callback
 +
      threshold->when(FL_WHEN_ENTER_KEY | FL_WHEN_CHANGED | FL_WHEN_RELEASE);
 +
      threshold->align(FL_ALIGN_TOP);
 +
      threshold->minimum(0);
 +
      threshold->maximum(255);
 +
      threshold->step(1);
 +
      threshold->value((double)*thresholdValue);  // initialize the threshold to the value passed as a parameter
 +
      threshold->box(FL_PLASTIC_DOWN_BOX);
 +
 
 +
      /* Text output ... note: we don't declare text_output because it is declared in the guiUtilities library  */
 +
 
 +
      text_output = new Fl_Multiline_Output(text_output_x, text_output_y, text_output_width, text_output_height,"" );
 +
      text_output->align(FL_ALIGN_TOP | FL_ALIGN_CENTER );
 +
      text_output->labelsize(12);
 +
      text_output->textsize(12);
 +
      //text_output->color(FL_GREEN);
 +
      text_output->value("");
 +
      //text_output->box(FL_THIN_DOWN_FRAME);  // matches the image display frames
 +
      text_output->box(FL_PLASTIC_DOWN_BOX);  // rounded edges for something more visually appealing
 +
 
 +
    start_protoComponent_GUI->end();  // end of the group
 +
 +
Now we are in a position to actually create the GUI. We do this by instantiating a window class <code>Fl_Double_Window</code>, position it, enable double buffering to make images in video sequences transition smoothly, display the window, add the group of GUI widgets, and then redraw the window.  We call the ''FLTK'' function <code>Fl::check();</code> to display the window.
  
 +
    // create main window
 +
 
 +
    DVwindow = new Fl_Double_Window(window_width-border_width,window_height-border_height,"The protoComponentGUI Example");
 +
    DVwindow->position(0,0);
 +
 +
    Fl::visual(FL_DOUBLE|FL_INDEX); // enable double buffering of the window
 +
 +
    DVwindow->end();
 +
    DVwindow->show();
 +
 +
    // add the GUI
 +
 +
    DVwindow->add(start_protoComponent_GUI);
 +
    DVwindow->redraw();
 +
    Fl::check();
 +
 +
We can now interact with the widgets.  First we display some text in the <code>text_output</code> widget using the <code>message()</code> function.  This function is one of the utilities that is provided by the ''guiUtilities'' library. 
  
Apart from the way that the commands are parsed and the form of the reply, the key thing to note here is the fact that the value of <code>MyModule::thresholdValue</code> is updated. Since <code>myThread</code> references this variable, it too is updated and the updated value is used in the thread.  
+
Having done that, we are done with the GUI definition.  We now revert to the normal YARP thread loop.   Notice however, that we include two ''FLTK'' method calls inside this loop, one to redraw the window and one the tell ''FLTK'' that the window has been re-drawn and needs to be redisplayed.  
  
bool MyModule::respond(const Bottle& command, Bottle& reply)  
+
    /* write some text in the window ...                                                              */
{
+
    /* note that function message() is defined in guiUtilities as a general-purpose routine to write   */
   string helpMessage =  string(getName().c_str()) +
+
    /* to the predefined display widget text_output ... notice how we didn't declare text_output above */
                        " commands are: \n" + 
+
    /* we didn't have to because it is declared in guiUtilities                                        */
                        "quit \n" +
+
                        "set thr <n> ... set the threshold \n" +
+
                        "(where <n> is an integer number) \n";
+
 
   
 
   
  reply.clear();  
+
    message("Waiting to start .... image statistics will be displayed here");
 
   
 
   
  if (command.get(0).asString()=="quit") {
 
        reply.addString("quitting");
 
        return false;   
 
    }
 
    else if (command.get(0).asString()=="help") {
 
      cout << helpMessage;
 
      reply.addString("ok");
 
    }
 
    else if (command.get(0).asString()=="set") {
 
      if (command.get(1).asString()=="thr") {
 
          thresholdValue = command.get(2).asInt(); // set parameter value
 
          reply.addString("ok");
 
      }
 
    }
 
    return true;
 
}
 
 
 
   
 
   
However, for any of this to work, we have to set up a port in the first place. We put port declaration in the private data member part of <code>MyModule</code> class
+
    /*************************************************************************************/
 +
    /*  This is where the definition of the GUI ends and the normal run() loop begins  */
 +
    /*************************************************************************************/
 +
   
 +
    while (isStopping() != true) { // the thread continues to run until isStopping() returns true
 +
 
 +
      DVwindow->redraw();
 +
 +
      Fl::check();        // refresh the GUI  .... we do it this way rather than calling Fl::run() as we nomally would
 +
                            // because we do not want to cede control to the event loop
  
string handlerPortName;
+
Further down this loop we have occasion to interact with the ''FLTK'' widgets, e.g. to read an image from a port, copy it to the local format suitable for display, and then display it. 
Port handlerPort;      //a port to handle messages
+
  
and open it in the <code>configure()</code> method, viz.
+
      /*** read colour image ... do not block if image is not received ***/
 
+
/*
+
  * attach a port of the same name as the module (prefixed with a /) to the module
+
  * so that messages received from the port are redirected to the respond method
+
  */
+
 
   
 
   
  handlerPortName "/";
+
      rgbYARPImage = colourImagePortIn->read(false);
  handlerPortName += getName();         // use getName() rather than a literal
+
   
 +
      if (rgbYARPImage != NULL) {
 +
   
 +
          rgb_width = rgbYARPImage->width();
 +
          rgb_height = rgbYARPImage->height();
 +
          rgb_depth  = 3;
 +
   
 +
          if (debug) printf("protoComponentGUI: rgb width = %d, rgb height = %d, rgb depth = %d\n",rgb_width, rgb_height, rgb_depth);
 
    
 
    
if (!handlerPort.open(handlerPortName.c_str())) {          
+
          if (rgbDVImage == NULL) {
    cout << getName() << ": Unable to open port " << handlerPortName << endl;
+
              rgbDVImage = new DVimage(rgb_width, rgb_height, rgb_depth);
    return false;
+
          }
}
+
 
   
 
   
  attach(handlerPort);                  // attach to port
+
   
 +
          /*  now copy the image to local format */
 
    
 
    
  attachTerminal();                     // attach to terminal
+
          for (x = 0; x < rgb_width; x++) {
 +
            for (y = 0; y < rgb_height; y++) {
 +
                rgbPixel = rgbYARPImage->safePixel(x,y);  
 +
                rgbDVImage->put_pixel(x, y, rgbPixel.r, 0);
 +
                rgbDVImage->put_pixel(x, y, rgbPixel.g, 1);
 +
                rgbDVImage->put_pixel(x, y, rgbPixel.b, 2);
 +
            }
 +
          }
 +
 
 +
          display1->draw(rgbDVImage);
 +
      }
 +
      else {
 +
          if (debug) printf("protoComponentGUI: colour image not received\n");
 +
      }
  
Interrupt it in the <code>interrupt()</code> method, viz.
+
We also read the image statistics from another port, process them, and then display them in a text box.
 
+
 
handlerPort.interrupt();
+
      /* read the image statistics ... do not block if bottle is not received*/
 
+
Close it in the <code>close()</code> method, viz.
+
      statisticsMessage = statisticsPortIn->read(false);
 
+
     
  handlerPort.close();
+
      if (statisticsMessage != NULL) {
 
+
=== Remote Connection ===
+
          /* for some strange reason, YARP puts double quotes around every individual string in a bottle so we strip them here */
Note that the <code>handlerport</code> can be used not only by other modules but also interactively by a user through the <code>yarp rpc</code> directive, viz.:
+
   
 
+
          j=0;
  yarp rpc /myModule
+
          for (i=0; i<min(STRINGLENGTH-1,(int)strlen(statisticsMessage->toString().c_str()));i++) {
 
+
            if (statisticsMessage->toString().c_str()[i]!='\"') {
This opens a connection from a terminal to the port and allows the user to then type in commands and receive replies from the <code>respond()</code> method.
+
                modifiedString[j] = statisticsMessage->toString().c_str()[i];
 +
                j++;
 +
            }
 +
          }
 +
          modifiedString[j]='\0';
 +
   
 +
 +
          /* now copy the message to the display */
 +
 +
          message(modifiedString);
 +
          if (debug) cout << "protoComponentGUIThread: statistics message is " << modifiedString << endl;   
 +
      }
 +
      else {
 +
          if (debug) printf("protoComponentGUI: statistics not received\n");
 +
      }
  
 +
Finally, we can use the threshold value set by the ''FLTK'' valuator and send it on a port (to <code>protoComponent</code>).
 +
 +
      /*** write the threshold ***/
 +
 +
      VectorOf<int> &thresholdVector = thresholdPortOut->prepare();
 +
      thresholdVector.resize(1);
 +
      thresholdVector(0) = *thresholdValue;
 +
 
 +
      thresholdPortOut->write();
  
== Documentation and Coding Guidelines ==
+
== Test Applications ==
  
'''Note''': This paragraph has been copied in Section 11 of the manual (Guidelines).
+
As we noted at the outset, in a Component-Based Software Engineering (CBSE) project, such as CINDY, the source code application file is replaced by the application script file or application XML file that runs the various components and connects them together in a working system. Thus, CINDY applications, i.e. collections of inter-connected YARP modules, are described in XML and launched using a utility called ''gyarpmanager''.  Refer to the [[Software Users Guide]] for more details on how to run these application descriptions.
  
RobotCub code follows some fairly strict documentation and coding standards defined in Section III of  [http://www.robotcub.org/index.php/robotcub/more_information/deliverables/deliverable_8_2_pdf RobotCub Deliverable 8.2].
+
In this section, we provide two test applications.
  
For convenience, here are the  
+
The first test application shows how to configure and run a simple application to use the <code>protoComponent</code> by connecting it to other components that provide input images and display the output images. This application uses <code>yarpview</code> modules to view the images. The threshold is modified online by sending commands  to <code>protoComponent</code> from the command line in a terminal window.
  
* [[DREAM File Organization Guidelines]]
+
The second test application shows how to configure and run a simple application to use <code> protoComponent</code> and <code> protoComponentGUI</code> together.  In this case, the images are displayed in the GUI rather than <code>yarpview</code> displays and the threshold is modified interactively using the GUI controls.
* [[DREAM Documentation Guidelines]]
+
* [[DREAM Coding Guidelines]]
+
 
+
Please take the time to read through the three documents.   
+
 
+
 
+
As we move towards the creation of a release version of the DREAM software, we will begin to enforce a sub-set of these guidelines as mandatory standards.  The current set of standards is set out in [[DREAM Software Standards]]. '''Ultimately, all modules to be included in the standard DREAM release version will have to comply with these standards.'''
+
 
+
 
+
The principal documentation for <code>myModule</code> is provided in the full example at the end of this page.
+
 
+
== Application Description ==
+
 
+
DREAM applications, i.e. collections of inter-connected YARP modules, are described in XML and launched using an automatically-generated GUI.  Refer to [[Managing Applications]] for more details on how to write these application descriptions.
+
 
+
An application description containing an example invocation of the <code>myModule</code> with some command-line parameters is shown below.
+
  
 +
Both applications have some some command-line parameters for illustration. Remember that these command-line parameter values have priority over the same parameter values specified in the relevant configuration file, which in turn have priority over the default values provided in the source code.
  
 
  <application>
 
  <application>
+
  <name>Demo of protoComponent</name>
  <name>Test myModule</name>
+
 
   
 
   
 
  <dependencies>
 
  <dependencies>
 
     <port>/robot/cam/left</port>
 
     <port>/robot/cam/left</port>
  </dependencies>  
+
  </dependencies>
 
   
 
   
 
  <module>
 
  <module>
     <name>myModule</name>
+
     <name>protoComponent</name>
     <parameters>--threshold 128</parameters>
+
     <parameters>--context components/protoComponent/config </parameters>
     <node>dream1</node>
+
    <node>cindy1</node>
     <tag>myModule</tag>
+
    <tag>protoComponent</tag>
  </module>  
+
</module>
 +
 +
<module>
 +
    <name>imageSource</name>
 +
    <parameters>--context components/imageSource/config</parameters>
 +
     <node>cindy1</node>
 +
     <tag>imageSource</tag>
 +
  </module>
 
   
 
   
 
  <module>
 
  <module>
 
     <name>yarpview</name>
 
     <name>yarpview</name>
     <parameters>--name /rgbImage --x 000 --y 0 --synch</parameters>
+
     <parameters>--name /inputImage --x 000 --y 000 --w 320 --h 318 </parameters>
    <node>dream1</node>
+
    <node>cindy1</node>
     <tag>left_image</tag>
+
     <tag>input_image</tag>
  </module>  
+
  </module>
 
   
 
   
 
  <module>
 
  <module>
 
     <name>yarpview</name>
 
     <name>yarpview</name>
     <parameters>--name /binaryImage --x 350 --y 0 --synch</parameters>
+
     <parameters>--name /binaryImage --x 320 --y 000 --w 320 --h 318 </parameters>
     <node>dream1</node>
+
     <node>cindy1</node>
     <tag>right_image</tag>
+
     <tag>plot_image</tag>
  </module>  
+
  </module>
 
   
 
   
 
  <connection>
 
  <connection>
 
   <from>/robot/cam/left</from>
 
   <from>/robot/cam/left</from>
   <to>/myModule/image:i</to>
+
   <to>/inputImage</to>
 
   <protocol>tcp</protocol>
 
   <protocol>tcp</protocol>
 
  </connection>
 
  </connection>
Line 786: Line 1,449:
 
  <connection>
 
  <connection>
 
   <from>/robot/cam/left</from>
 
   <from>/robot/cam/left</from>
   <to>/rgbImage</to>
+
   <to>/protoComponent/image:i</to>
 
   <protocol>tcp</protocol>
 
   <protocol>tcp</protocol>
  </connection>  
+
  </connection>
 
   
 
   
 
  <connection>
 
  <connection>
   <from>/myModule/image:o</from>
+
   <from>/protoComponent/image:o</from>
 
   <to>/binaryImage</to>
 
   <to>/binaryImage</to>
 
   <protocol>tcp</protocol>
 
   <protocol>tcp</protocol>
  </connection>  
+
  </connection>
 
   
 
   
 
  </application>
 
  </application>
 
  
To run the application, you simple need to run the XML application description shown in the previous section.  To do this, however, you need to have a couple of new things installed:
+
<application>
 
+
<name>Demo of protoComponentGUI</name>
 
+
* Python (this is used to interpret the DREAM application description programs and launch DREAM applications);
+
* the <code>dreamapp</code>  pseudo-command for launching the Python application manager.  This is no more than a simple invocation of Python to run the application manager and interpret the XML application descripton, viz. <code>python $DREAM_ROOT\app\default\scripts\manager.py %1</code>.
+
 
+
 
+
Refer to [[Prepare your system for running applications]] for details of how to get these resources .
+
 
+
 
+
Do an update on your DREAM repository to make sure you have the <code>icubapp</code>  pseudo-command. Alternatively, you can launch the python application manager directly (see below).
+
 
+
 
+
Once you have done all this, you are ''almost'' ready to run your application.  There's just one more thing to be aware of.
+
 
+
 
+
You need to start an instance of <code>yarprun --server</code>  on the local machine (for a complete explanation see [[Cluster management]]).  This <code>yarprun</code> is what the node in an XML application description gets mapped to.  At present, the standard for creating these <code>yarprun</code>s is for the <code>yarprun</code> argument to be the name of the node identifier in the XML <code><node></node></code> field but prefixed by a / to make it explicit that the argument is a port.
+
 
+
So, if you have used, for example, <code><node>dream1</node></code> in your <code><module></code> description in the XML file, then you would do
+
 
   
 
   
  PC> yarprun --server /dream1
+
  <dependencies>
 
+
    <port>/robot/cam/left</port>
In general, at present (this may change in the future), you need to do a
+
</dependencies>
 
   
 
   
  PC> yarprun --server /<mc_n>
+
  <module>
 
+
    <name>protoComponentGUI</name>
for each <mc_n> node values specified in the xml file. 
+
    <parameters>--context components/protoComponentGUI/config </parameters>
 
+
    <node>cindy1</node>
 
+
    <tag>protoComponentGUI</tag>
These <code>yarprun</code> commands are run on the machine to which that node is mapped.  An XML <code><node></code> is a logical machine and the <code>yarprun</code> associates it with the physical machine on which it to be instantiated.
+
  </module>
 
+
 
+
You can now launch an application. Simply navigate to the directory where the XML file resides (typically <code>$DREAM_ROOT/app/myModule/scripts</code>) and do
+
 
   
 
   
  PC> runapp myModule.xml
+
  <module>
 
+
    <name>protoComponent</name>
Alternatively, if you prefer, you can launch the Python application manager directly:
+
    <parameters>--context components/protoComponent/config </parameters>
 
+
    <node>cindy1</node>
PC> manager.py myModule.xml
+
    <tag>protoComponent</tag>
 
+
</module>
assuming that <code>$DREAM_ROOT\app\default\scripts\</code> is defined in you path and assuming <code>.py</code> files are associated with Python.
+
 
+
<module>
In either case, doing this will launch a GUI with which you can then "Run Modules" and "Connect" the ports by clicking on the appropriate buttons.
+
    <name>imageSource</name>
 
+
    <parameters>--context components/imageSource/config --width 640 --height 480 </parameters>
 
+
    <node>cindy1</node>
NB: turn off your firewall before launching the application.
+
    <tag>imageSource</tag>
 
+
</module>
== Resources ==
+
 
+
<connection>
* [http://wiki.icub.org/yarp/specs/dox/user/html/index.html YARP home page]
+
  <from>/robot/cam/left</from>
 
+
  <to>/protoComponent/image:i</to>
* [http://wiki.icub.org/yarpdoc/yarp_resource_finder_tutorials.html Tutorial on the YARP Resource Finder Class]
+
  <protocol>tcp</protocol>
 
+
</connection>
* [http://wiki.icub.org/iCub/dox/html/module_standards.html Module Standards]
+
 
+
<connection>
* [[Resource finder overview]]
+
  <from>/protoComponent/image:o</from>
 
+
  <to>/protoComponentGUI/binaryimage:i</to>
* [http://wiki.icub.org/iCub/dox/html/icub_resource_finder_basic.html How to organize the command line parameters of your modules]
+
  <protocol>tcp</protocol>
 
+
</connection>
* [http://wiki.icub.org/iCub/dox/html/icub_resource_finder_advanced.html Organizing Parameters: Advanced Tutorial]
+
 
+
<connection>
* [http://wiki.icub.org/iCub/dox/html/icub_tutorial_module.html Using the module helper class to write a program]
+
  <from>/protoComponent/statistics:o</from>
 
+
  <to>/protoComponentGUI/statistics:i</to>
* [http://wiki.icub.org/yarpdoc/d9/d26/classyarp_1_1os_1_1RFModule.html RFModule Class Reference]
+
  <protocol>tcp</protocol>
 
+
</connection>
* [http://wiki.icub.org/yarpdoc/d1/d03/classyarp_1_1os_1_1Module.html Module Class Reference]
+
 
+
<connection>
* [http://wiki.icub.org/iCub/dox/html/coding_standards.html Coding and Documentation Standards]
+
  <from>/robot/cam/left</from>
 +
  <to>/protoComponentGUI/colourimage:i</to>
 +
  <protocol>tcp</protocol>
 +
</connection>
 +
 +
<connection>
 +
  <from>/protoComponentGUI/threshold:o</from>
 +
  <to>/protoComponent/threshold:i</to>
 +
  <protocol>tcp</protocol>
 +
</connection>
 +
 +
</application>
  
* [http://wiki.icub.org/iCub/dox/html/group__icub__exampleModule.html exampleModule]
+
To run the application, follow the instruction in the [[Software Users Guide]].
  
* [[Cluster management]]
+
== Software Engineering Standards ==
  
* [http://wiki.icub.org/iCub/dox/html/group__icub__exampleApplication.html exampleApplication]
+
Finally, note that CINDY follows a set of recommended software engineering standardi, as follows.
  
* [http://wiki.icub.org/iCub/dox/html/icub_tutorials.html iCub tutorials]
+
* [[Standards for File Organization]]
 +
* [[Standards for Internal Documentation]]
 +
* [[Standards for Component Functionality]]
 +
<!-- * [[Standards for Testing]]-->
 +
* [[Standards for Programming Style]]
 +
* [[Standards for Programming Practice]]
  
 +
Please take the time to read through these documents.
  
== The Complete <code>myModule</code> Example ==
 
  
The complete code for <code>myModule</code> is [[The myModule Example | here]].
+
----
 +
Return to [[The CINDY Cognitive Architecture]] main page.

Latest revision as of 03:19, 17 February 2015

Overview

This guide describes two examples of what is involved when developing a YARP-based component that is compliant with recommended standards for software engineering.

The first example, protoComponent, implements some very simple image processing and analysis (binary segmentation using a supplied threshold and then count the number of foreground pixels).

The second example, protoComponentGUI, explains how to write a component that implements a simple graphic use interface. In this case, the GUI allows the user to set the threshold with a slider widget and then sends the threshold to protoComponent. It receives some statistics from protoComponent, specifically the number of foreground pixels and the current time, and writes them to a text display. It also receives the binary image from protoComponent and displays it along with the original colour image that it receives from the source that also feeds protoComponent.

Both examples are accompanied by a test application, again adhering to the recommended standards.

File Organization

As noted in the Mandatory Standards for File Organization, the implementation of a typical CINDY component comprises four files. These are the interface file and three implementation files:

  • The interface file is a header file, e.g. protoComponent.h, with the class declarations, method prototype declarations, and function prototype declarations, but no method or function implementations. It also contains the Doxygen documentation comments explaining the purpose and usage of the component (see Mandatory Standards for Internal Documentation).
  • The implementation files contains the source code for the implementation of each class method (C++) or the source code of each function (C). For convenience, the implementation is separated in three files:
  1. The first source code file — e.g. protoComponentMain.cpp — contains the main() function that instantiates the module object and calls the runModule method to effect the configuration, coordination, computation, and communication for that component.
  2. The second source code file — e.g. protoComponentConfiguration.cpp — contains the code that handles the component’s configuration and coordination functionality.
  3. The third source code file — e.g. protoComponentComputation.cpp — contains the code that handles the component’s computation and communication functionality.

Therefore, the four protoComponent files are:

protoComponent.h 
protoComponentMain.cpp
protoComponentConfiguration.cpp 
protoComponentComputation.cpp

and the four protoComponentGUI files are:

protoComponentGUI.h 
protoComponentGUIMain.cpp
protoComponentGUIConfiguration.cpp 
protoComponentGUIComputation.cpp

All of these files should be placed in the src directory.

Note that in a Component-Based Software Engineering (CBSE) project, such as CINDY, the source code application file is replaced by the application script file or application XML file that runs the various components and connects them together in a working system (see #Application Description).

Example Code

All the code for these examples is available in the CINDY software repository. For convenience, you can also review the code here:

How This Guide Is Organized

There are four main parts to this guide, in addition to this overview, some focussing on the protoComponent example and others on the protoComponentGUI example.

Component Configuration and Coordination: the RFModule Class

We begin with the functionality associated with configuration and coordination, i.e. with the protoComponentConfiguration.cpp and protoComponent.h files. This functionality revolves around the RFModule class. The protoComponentGUIConfiguration.cpp and protoComponentGUI.h files have essentially the same structure.

This section also deals with the main() function, i.e. with the protoComponentApplication.cpp file. It shows how to instantiate a module derived from the RFModule class, set the default configuration file and path for the resource finder, and run the module. This allows the component to be configured using the resource finder.

Once this is done, the derived module then instantiates a Thread or a RateThread object and launches it, passing to it as arguments all the relevant resources (e.g. port names and parameter values) located by the resource finder.

Finally, it is also responsible for shutting down the thread gracefully by stopping the thread, interrupting any port communications, and closing the ports.

Component Computation and Communication: the Thread and RateThread Classes

We then address the functionality associated with computation and communication, i.e. with the protoComponentComputation.cpp and protoComponent.h files. This functionality revolves around the Thread and RateThread classes: how to access the parameters passed to it from the derived RFModule object and how to perform some useful work.

GUI Component Computation and Communication: the FLTK and guiUtilities Libraries

We now show how you can write your own graphic user interface for the protoComponent component. This will be implemented as a separate stand-along component protoComponentGUI. As noted above, the functionality associated with configuration and coordination, i.e. with the protoComponentGUIConfiguration.cpp and protoComponentGUI.h files, is essentially the same as for the protoComponent example. Again, this functionality revolves around the RFModule class.

Instead, this section addresses the functionality associated with computation and communication, i.e. with the protoComponentGUIComputation.cpp and protoComponent.h files. Again, the functionality revolves around the Thread and RateThread classes but here we explain how to configure the graphic user interface with the FLTK and guiUtilities libraries.

Test Applications

This section describes two test applications.

The first test application shows how to configure and run a simple application to use the protoComponent by connecting it to other components that provide input images and display the output images. This application uses yarpview modules to view the images. The threshold is modified online by sending commands to protoComponent from the command line in a terminal window.

The second test application shows how to configure and run a simple application to use protoComponent and protoComponentGUI together. In this case, the images are displayed in the GUI rather than yarpview displays and the threshold is modified interactively using the GUI controls.

Component Configuration and Coordination: The RFModule Class

The starting point in writing any CINDY component is to develop a sub-class of the yarp::os::RFModule class.

First, we define a sub-class, or derived class, of the yarp::os::RFModule class. The module's variables - and specifically the module's parameters and ports - go in the private data members part and you need to override three methods:

  • bool configure();
  • bool interruptModule();
  • bool close();

We will see later that there are three other methods which can be useful to override:

  • bool respond();
  • double getPeriod();
  • bool updateModule();

In the following, we assume we are writing a module named protoComponent. This module will be implemented as a sub-class yarp::os::RFModule called ProtoComponent (it is a capital P because it is a sub-class). For convenience, the header comments have been removed.

/** @file protoComponent.h  Interface file for the example CINDY component */

#include <iostream>
#include <string>

#include <yarp/sig/all.h>
#include <yarp/os/all.h>
#include <yarp/os/RFModule.h>
#include <yarp/os/Network.h>
#include <yarp/os/Thread.h>
 
using namespace std;
using namespace yarp::os; 
using namespace yarp::sig;
  
class ProtoComponentThread : public Thread {

private:

   /* class variables */

   bool               debug;
   int                x, y;
   PixelRgb           rgbPixel;
   ImageOf<PixelRgb> *image;
   int               *thresholdValue;   
   VectorOf<int>     *thresholdVector;
   int               numberOfForegroundPixels;

   /* thread parameters: they are pointers so that they refer to the original variables in protoComponent */

   BufferedPort<ImageOf<PixelRgb> > *imagePortIn;
   BufferedPort<VectorOf<int> >     *thresholdPortIn; 
   BufferedPort<ImageOf<PixelRgb> > *imagePortOut; 
   BufferedPort<Bottle>             *statisticsPortOut; 
  

  public:
 
    /* class methods */
 
    ProtoComponentThread(BufferedPort<ImageOf<PixelRgb> > *imageIn, 
                         BufferedPort<VectorOf<int> >     *thresholdIn, 
                         BufferedPort<ImageOf<PixelRgb> > *imageOut,
                         BufferedPort<Bottle>             *statisticsOut, 
                         int *threshold );
    bool threadInit();     
    void threadRelease();
    void run(); 
};


class ProtoComponent:public RFModule {

   /* module parameters */

   string moduleName;
   string imageInputPortName;
   string thresholdInputPortName;
   string imageOutputPortName;
   string statisticsOutputPortName;  
   string handlerPortName;
   string cameraConfigFilename;
   float  fxLeft,  fyLeft;          // focal length
   float  fxRight, fyRight;         // focal length
   float  cxLeft,  cyLeft;          // coordinates of the principal point
   float  cxRight, cyRight;         // coordinates of the principal point
   int    thresholdValue;

   /* class variables */

   BufferedPort<ImageOf<PixelRgb> > imageIn;       // example image input port
   BufferedPort<VectorOf<int> >     thresholdIn;   // example vector input port 
   BufferedPort<ImageOf<PixelRgb> > imageOut;      // example image output port
   BufferedPort<Bottle>             statisticsOut; // example bottle output port
   Port handlerPort;                               // a port to handle interactive messages (also uses bottles)

   /* pointer to a new thread to be created and started in configure() and stopped in close() */

   ProtoComponentThread *protoComponentThread;

public:
  
   bool configure(yarp::os::ResourceFinder &rf); // configure all the module parameters and return true if successful
   bool interruptModule();                       // interrupt, e.g., the ports 
   bool close();                                 // close and shut down the module
   bool respond(const Bottle& command, Bottle& reply);
   double getPeriod(); 
   bool updateModule();
}; 

Here we deal with the various issues of implementing the module, particularly configuration of the component from external parameters and files, and run-time interaction.

The actual work to be done by the component is accomplished by another sub-class of a Thread class. The definition of this sub-class is also included in the interface header file, e.g. protoComponent.h but the implementation is effected in a separate source file, e.g. protoComponentComputation.cpp.

Perhaps the trickiest part of writing the software to implement a component is understanding the way that the RFModule and Thread share the work between them and how they interact. That's exactly what we will explain in to following, once we have covered how the RFModule object handles all the configuration and coordination functionality.

First, some clarification. By configuration we mean the ability to specify the way that a given component is used. There are two aspects to this:

  1. How the component is presented (i.e. which particular interfaces are used: the names of ports used, the name of the configuration file, the path to the configuration file, the name of the component, and the name of the robot) and
  2. The component parameters that govern its behaviour (e.g. thresholds, set-points, and data files)

We refer to these collectively as resources. Typically, the configuration file name, the configuration file path (called the context), the component name, and the robot name are specified as command-line parameters, while all the remaining resources, including the names of the ports, are typically specified in the configuration file.

Note that all resources are handled the same way using the ResourceFinder which not only greatly simplifies the process of finding the resources but also simplifies the process of parsing them.

It's worth noting that parameters that are specified in the configuration file can also be specified in the command-line if you wish. The reverse is also true, with some restrictions (e.g. it only makes sense to specify the configuration file and the configuration file path on the command-line). Finally, modules should be written so that default values are provided for all resources so that the module can be launched without any parameters. Again, the ResourceFinder makes it easy to arrange this.

Right now, what's important to grasp is that all these configuration issues are implemented by

  • Instantiating your component as a derived sub-class of RFModule in the main() function (e.g. in protoComponentMain.cpp),
  • Preparing the ResourceFinder in the main() function by setting the default configuration file and its path,
  • Overriding the yarp::os::RFModule::configure() method (e.g. in protoComponentConfiguration.cpp) to parse all the parameters from the command-line and the configuration file.
  • Launching your component by calling the yarp::os::RFModule::runModule() method from main(),

The following sections explain the implementation details of each aspect of this set-up and configuration.

Instantiating a Derived Sub-Class of RFModule, Configuring the Resource Finder, and Running the Module

The main() function in the protoComponentMain.cpp file is responsible for instantiating a module derived from the RFModule class, setting the default configuration file and path for the resource finder, and running the module. This allows the component to be configured using the resource finder (something that is actually accomplished by the code in protoComponentConfiguration.cpp).

/* protoComponentMain.cpp Application file for the example CINDY component */

int main(int argc, char * argv[])
{
  /* initialize yarp network */ 
  
  Network yarp;
 
  /* create your module */
 
  ProtoComponent protoComponent; 
 
  /* prepare and configure the resource finder */
 
  ResourceFinder rf;
  rf.setVerbose(true);
  rf.setDefaultConfigFile("protoComponent.ini");          // can be overridden by --from parameter
  rf.setDefaultContext("protoComponent/configuration");   // can be overridden by --context parameter
  rf.configure("CINDY_ROOT", argc, argv);                 // environment variable with root of configuration path
  
  /* run the module: runModule() calls configure first and, if successful, it then runs */
 
  protoComponent.runModule(rf);
 
  return 0;
}

There are a few important points to notice in the code above.


  • Initialization of the configuration file in the resource finder object
  • Initialization of the path to the configuration file in the resource finder object
  • Initialization of the environmental variable that defines the root of the configuration path in the resource finder object
  • The runModule method is called to launch the module and do the configuration using the resource finder object passed as an argument


The first two require some additional explanation which we provide next.

Configuration File

Configuration can be changed by changing configuration files. The configuration file which the component reads can be specified as a command line option.

--from protoComponent.ini

The component should set a default configuration file using yarp::os::ResourceFinder::setDefaultConfigFile("protoComponent.ini"). This should be done in the main() function before running the module.

The value set by this method is overridden by the --from parameter (specified either during the command-line invocation or in the component configuration file; the command-line has priority over the configuration file if both are specified).

The .ini file should usually be placed in the $CINDY_ROOT/release/components/protoComponent/config sub-directory.

Context

The relative path from $CINDY_ROOT/release to the directory containing the configuration file is specified from the command line by

--context  components/protoComponent/config

The module should set a default context using yarp::os::ResourceFinder::setDefaultContext("components/protoComponent/config"). This should be done in the main() function in protoComponentMain.cpp before launching the component.

This is overridden by the --context parameter (again, specified either during the command-line invocation or in the component configuration file; the command-line has priority over the configuration file if both are specified).

Configuration: Overriding the yarp::os::RFModule::configure() method

The method that overrides yarp::os::RFModule::configure() is defined in protoComponentConfiguration.cpp. It uses the resource finder to parse all the parameters from the command-line and the configuration file and assign values appropriately.

The key thing to keep in mind here is that it must be possible to externally reconfigure how the component interfaces with other components without having to modify any source code. This is why so much information is required when starting up the component and why the resource finder is so useful and important.

Module Name and Port Names

You should ensure that it is possible to specify the names of any ports created by a module via configuration. There are two aspects to this: the stem of the port name and the port name itself.

A command-line option of

--name altName

sets the name of the module and will cause the module to use "/altName" as a stem for all port names provided the port names are generated using the yarp::os::RFModule::getName() method. Note that he leading "/" prefix has to be added explicitly to the module name to create the port name.

The module should set a default name (and, hence, a default stem) using yarp::os::RFModule::setName("protoComponent").

This is overridden by the --name parameter but you must check for this parameter and call setName() accordingly, e.g.

string moduleName;
 
moduleName = rf.check("name", 
             Value("protoComponent"), 
             "module name (string)").asString();    

setName(moduleName.c_str());  // do this before processing any port name parameters

The port names should be specified as parameters, typically as key-value pairs in the .ini configuration file, e.g.

imageInputPort    /image:i
imageOutputPort   /image:o

These key-value pairs can also be specified as command-line parameters, viz: --imageInputPort /image:i --imageOutputPort /image:o

The component should set a default port name using the ResourceFinder, e.g using yarp::os::ResourceFinder::check();

For example

string inputPortName  = "/";
       inputPortName += getName(
                        rf.check("imageInputPort",
                        Value("/image:i"),
                        "Input image port (string)").asString()
                        );

will assign to inputPortName the value /altName/image:i if --name altName is specified as a parameter. Otherwise, it would assign /protoComponent/image:i On the other hand, it would assign /protoComponent/altImage:i if the key-value pair myInputPort /altImage:i was specified (either in the .ini file or as a command-line parameter) but not the --name altName

When providing the names of ports as parameter values (whether as a default value in ResourceFinder::check, as a value in the key-value list in the .ini configuration file, or as a command line argument), you always include the leading /.

All this code goes in the configure() method in protoComponentConfiguration.cpp.

Which Parameters Are Parsed Automatically?

Parsing the --from and --context parameters is handled automatically by the RFModule but --name and --robot must be handled explicitly.

As noted above, you would handle the --name parameter by using ResourcFinder::check() to parse it and get the parameter value, then user setName() to set it. You should do this before proceeding to process any port name parameters, otherwise the wrong stem will be used when constructing the port names from the parameter values.

Configuration File Parameters

The configuration file, typically named protoComponent.ini and located in the $CINDY_ROOT/release/components/protoComponent/config directory, contains a key-value list: a list of pairs of keywords (configuration parameter names) and values (configuration parameter values), e.g.

imageInputPort   /altImage:i
imageOutputPort  /altImage:o
threshold 9
...

These parameters are parsed using the ResourceFinder within an RFModule object (i.e. by methods inherited by your module such as yarp::os::Searchable::check()).


Typically, key-value pairs specify the parameters and their values that govern the behaviour of the module, as well as the names of the module ports, should you wish to rename them.

Other Configuration Files

Apart from processing the parameters in the configuration file protoComponent.ini, it's often necessary to access configuration data in other files. For example, you might want to read the intrinsic camera parameters from a camera calibration file. Let's assume this configuration file is called cameras.ini and we wish to extract the principal points of the left and right cameras. The coordinates of the principle points, and other intrinsic camera parameters, are stored as a sequence of key-value pairs:

cx 157.858
cy 113.51 

Matters are somewhat complicated by the fact that we need to read two sets of coordinates, one for the left camera and one for the right. Both sets have the same key associated with them so the left and right camera parameters, including the principal point coordinates, are typically listed under different group headings, viz.

[CAMERA_CALIBRATION_RIGHT]
...
cx 157.858
cy 113.51
...
 
[CAMERA_CALIBRATION_LEFT]
...
cx 174.222
cy 141.757
...

So, to read these two pairs of coordinates, we need to

  • find the name of the file (e.g. cameras.ini)
  • locate the file (i.e. get its full path)
  • open the file and read its content
  • find the CAMERA_CALIBRATION_RIGHT and CAMERA_CALIBRATION_LEFT groups
  • read the respective cx and cy key values.


All of this is accomplished straightforwardly with the ResourceFinder and Property classes.


The first step is to get the name of the configuration file. This will typically be one of the key-value pairs in the module configuration file protoComponent.ini, e.g.

cameraConfig cameras.ini

so that it can be read in exactly the same way as the other parameters in the previous section, e.g. using yarp::os::Searchable::check().

The full path can then be determined by the yarp::os::ResourceFinder::findFile() method.

The contents of this file can then be read into a Property object using the yarp:os:Property::fromConfigFile() method.

Locating the required group (e.g. CAMERA_CALIBRATION_LEFT) is accomplished with the yarp: os:Property::findGroup() method.

This method returns a Bottle with the full key-value list under this group. This list can then be searched for the required key and value using the yarp::os::Searchable::check() method, as before.

Run-time Interaction

The respond() Method

Often, it is very useful for a user or another module to send commands to control the behaviour of the module, e.g. interactively changing parameter values.

We accomplish this functionality for the yarp::os::RFModule by overridding the yarp::os::RFModule::respond() method which can then be configured to receive messages from either a port (typically named /protoComponent) or the terminal. This is effected by the yarp::os::RFModule::attach(port) and yarp::os::RFModule::attachTerminal() methods, respectively. Attaching both the port and the terminal means that commands from both sources are then handled in the same way.

An example of how to change module parameters at run-time

In the following example, we handle three commands:

  • help
  • quit
  • set thr <n> ... set the threshold (where <n> is an integer number)

Apart from the way that the commands are parsed and the form of the reply, the key thing to note here is the fact that the value of ProtoComponent::thresholdValue is updated. Since protoComponent references this variable, it too is updated and the updated value is used in the thread.

bool ProtoComponent::respond(const Bottle& command, Bottle& reply) 
{
  string helpMessage =  string(getName().c_str()) + 
                        " commands are: \n" +  
                        "help \n" + 
                        "quit \n" + 
                        "set thr <n> ... set the threshold \n" + 
                        "(where <n> is an integer number) \n";

  reply.clear(); 

  if (command.get(0).asString()=="quit") {
       reply.addString("quitting");
       return false;     
   }
   else if (command.get(0).asString()=="help") {
      cout << helpMessage;
	  reply.addString("command is: set thr <n>");
   }
   else if (command.get(0).asString()=="set") {
      if (command.get(1).asString()=="thr") {
         thresholdValue = command.get(2).asInt(); // set parameter value
         reply.addString("ok");
      }
   }
   return true;
}

However, for any of this to work, we have to set up a port in the first place. We put the port declaration in the private data member part of ProtoComponent class

   string handlerPortName;
   ...
   Port handlerPort;                               // a port to handle interactive messages (also uses bottles)

and open it in the configure() method, viz.

   /*
    * attach a port of the same name as the module (prefixed with a /) to the module
    * so that messages received from the port are redirected to the respond method
    */

   handlerPortName =  "/";
   handlerPortName += getName();         // use getName() rather than a literal 
 
   if (!handlerPort.open(handlerPortName.c_str())) {           
      cout << getName() << ": Unable to open port " << handlerPortName << endl;  
      return false;
   }

   attach(handlerPort);                  // attach to port

Interrupt it in the interrupt() method, viz.

   handlerPort.interrupt();

Close it in the close() method, viz.

   handlerPort.close();

Remote Connection

Note that the handlerport can be used not only by other modules but also interactively by a user through the yarp rpc directive, viz.:

yarp rpc /protoComponent

This opens a connection from a terminal to the port and allows the user to then type in commands and receive replies from the respond() method.

An Example of how to Configure the Component

The following example summarizes how to handle all the configuration issues discussed above. This is taken directly from the protoComponent source code.

/** @file protoComponent.h  Interface file for the example CINDY component */

#include <iostream>
#include <string>

#include <yarp/sig/all.h>
#include <yarp/os/all.h>
#include <yarp/os/RFModule.h>
#include <yarp/os/Network.h>
#include <yarp/os/Thread.h>
 
using namespace std;
using namespace yarp::os; 
using namespace yarp::sig;
  
class ProtoComponentThread : public Thread {

private:

   /* class variables */

    bool               debug;
   int                x, y;
   PixelRgb           rgbPixel;
   ImageOf<PixelRgb> *image;
   int               *thresholdValue;   
   VectorOf<int>     *thresholdVector;
   int               numberOfForegroundPixels;

   /* thread parameters: they are pointers so that they refer to the original variables in protoComponent */

   BufferedPort<ImageOf<PixelRgb> > *imagePortIn;
   BufferedPort<VectorOf<int> >     *thresholdPortIn; 
   BufferedPort<ImageOf<PixelRgb> > *imagePortOut; 
   BufferedPort<Bottle>             *statisticsPortOut; 

  public:
 
    /* class methods */
 
    ProtoComponentThread(BufferedPort<ImageOf<PixelRgb> > *imageIn, 
                         BufferedPort<VectorOf<int> >     *thresholdIn, 
                         BufferedPort<ImageOf<PixelRgb> > *imageOut,
                         BufferedPort<Bottle>             *statisticsOut, 
                         int *threshold );
    bool threadInit();     
    void threadRelease();
    void run(); 
};


class ProtoComponent:public RFModule {

   /* module parameters */

   string moduleName;
   string imageInputPortName;
   string thresholdInputPortName;
   string imageOutputPortName;
   string statisticsOutputPortName;  
   string handlerPortName;
   string cameraConfigFilename;
   float  fxLeft,  fyLeft;          // focal length
   float  fxRight, fyRight;         // focal length
   float  cxLeft,  cyLeft;          // coordinates of the principal point
   float  cxRight, cyRight;         // coordinates of the principal point
   int    thresholdValue;

   /* class variables */

   BufferedPort<ImageOf<PixelRgb> > imageIn;       // example image input port
   BufferedPort<VectorOf<int> >     thresholdIn;   // example vector input port 
   BufferedPort<ImageOf<PixelRgb> > imageOut;      // example image output port
   BufferedPort<Bottle>             statisticsOut; // example bottle output port
   Port handlerPort;                               // a port to handle interactive messages (also uses bottles)

   /* pointer to a new thread to be created and started in configure() and stopped in close() */

   ProtoComponentThread *protoComponentThread;

public:
  
   bool configure(yarp::os::ResourceFinder &rf); // configure all the module parameters and return true if successful
   bool interruptModule();                       // interrupt, e.g., the ports 
   bool close();                                 // close and shut down the module
   bool respond(const Bottle& command, Bottle& reply);
   double getPeriod(); 
   bool updateModule();
}; 
/* protoComponentConfiguration.cpp  Implementation file for the example CINDY component */
 
/* 
 * Configure method ... use it to do component coordination, 
 * i.e. to configure your component at runtime
 */

bool ProtoComponent::configure(yarp::os::ResourceFinder &rf)
{    
   /* Process all parameters from both command-line and .ini file */

   /* get the module name which will form the stem of all module port names */

   moduleName            = rf.check("name", 
                           Value("protoComponent"), 
                           "module name (string)").asString();

   /*
    * before continuing, set the module name before getting any other parameters, 
    * specifically the port names which are dependent on the module name
    */
  
   setName(moduleName.c_str());

   /* now, get the rest of the parameters */

   /* get the name of the input and output ports, automatically prefixing the module name by using getName() */

   imageInputPortName    =      "/";
   imageInputPortName   +=      getName(
                                rf.check("imageInputPort", 
                                Value("/image:i"),
                                "Input image port (string)").asString()
                                );
   
   thresholdInputPortName =     "/";
   thresholdInputPortName +=    getName(
                                rf.check("thresholdInputPort", 
                                Value("/threshold:i"),
                                "Threshold input port (string)").asString()
                                );

   imageOutputPortName   =      "/";
   imageOutputPortName  +=      getName(
                                rf.check("imageOutputPort", 
                                Value("/image:o"),
                                "Output image port (string)").asString()
                                );

   statisticsOutputPortName   = "/";
   statisticsOutputPortName  += getName(
                                rf.check("statisticsOutputPort", 
                                Value("/statistics:o"),
                                "Output image port (string)").asString()
                                );


   /* get the threshold value */

   thresholdValue        = rf.check("threshold",
                           Value(8),
                           "Key value (int)").asInt();

   
   /* 
    * get the cameraConfig file and read the required parameter values cx, cy 
    * in both the groups [CAMERA_CALIBRATION_LEFT] and [CAMERA_CALIBRATION_RIGHT]
    */

   cameraConfigFilename  = rf.check("cameraConfig", 
                           Value("cameras.ini"), 
                           "camera configuration filename (string)").asString();

   cameraConfigFilename = (rf.findFile(cameraConfigFilename.c_str())).c_str();

   Property cameraProperties;

   if (cameraProperties.fromConfigFile(cameraConfigFilename.c_str()) == false) {
      cout << "protoComponent: unable to read camera configuration file" << cameraConfigFilename << endl;
      return 0;
   }
   else {
      cxLeft  = (float) cameraProperties.findGroup("CAMERA_CALIBRATION_LEFT").check("cx", Value(160.0), "cx left").asDouble();
      cyLeft  = (float) cameraProperties.findGroup("CAMERA_CALIBRATION_LEFT").check("cy", Value(120.0), "cy left").asDouble();
      cxRight = (float) cameraProperties.findGroup("CAMERA_CALIBRATION_RIGHT").check("cx", Value(160.0), "cx right").asDouble();
      cyRight = (float) cameraProperties.findGroup("CAMERA_CALIBRATION_RIGHT").check("cy", Value(120.0), "cy right").asDouble();
   }


   /* do all initialization here */
     
   /* open ports  */ 
       
   if (!imageIn.open(imageInputPortName.c_str())) {
      cout << getName() << ": unable to open port " << imageInputPortName << endl;
      return false;  // unable to open; let RFModule know so that it won't run
   }

   if (!thresholdIn.open(thresholdInputPortName.c_str())) {
      cout << getName() << ": unable to open port " << thresholdInputPortName << endl;
      return false;  // unable to open; let RFModule know so that it won't run
   }


   if (!imageOut.open(imageOutputPortName.c_str())) {
      cout << getName() << ": unable to open port " << imageOutputPortName << endl;
      return false;  // unable to open; let RFModule know so that it won't run
   }

   if (!statisticsOut.open(statisticsOutputPortName.c_str())) {
      cout << getName() << ": unable to open port " << statisticsOutputPortName << endl;
      return false;  // unable to open; let RFModule know so that it won't run
   }


   /*
    * attach a port of the same name as the module (prefixed with a /) to the module
    * so that messages received from the port are redirected to the respond method
    */

   handlerPortName =  "/";
   handlerPortName += getName();         // use getName() rather than a literal 
 
   if (!handlerPort.open(handlerPortName.c_str())) {           
      cout << getName() << ": Unable to open port " << handlerPortName << endl;  
      return false;
   }

   attach(handlerPort);                  // attach to port
 
   /* create the thread and pass pointers to the module parameters */

   protoComponentThread = new ProtoComponentThread(&imageIn, &thresholdIn, &imageOut, &statisticsOut, &thresholdValue);

   /* now start the thread to do the work */

   protoComponentThread->start(); // this calls threadInit() and it if returns true, it then calls run()
 
   return true ;      // let the RFModule know everything went well
                      // so that it will then run the module
}
/* protoComponentMain.cpp Application file for the example CINDY component */
 
#include "protoComponent.h" 
 
int main(int argc, char * argv[])
{
  /* initialize yarp network */ 
  
  Network yarp;
 
  /* create your module */
 
  ProtoComponent protoComponent; 
 
  /* prepare and configure the resource finder */
 
  ResourceFinder rf;
  rf.setVerbose(true);
  rf.setDefaultConfigFile("protoComponent.ini");          // can be overridden by --from parameter
  rf.setDefaultContext("protoComponent/configuration");   // can be overridden by --context parameter
  rf.configure("CINDY_ROOT", argc, argv);                 // environment variable with root of configuration path
  
  /* run the module: runModule() calls configure first and, if successful, it then runs */
 
  protoComponent.runModule(rf);
 
  return 0;
}

Doing Some Work: Instantiating and starting the protoComponentThread

Once the configuration is done (in protoComponentConfiguration.cpp), the derived module then instantiates a Thread (or RateThread) object and launches it (again, this is done in protoComponentConfiguration.cpp), passing to it as arguments all the relevant resources, e.g. port names and parameter values, located by the resource finder.

In the example above, this we done as follows.

   /* create the thread and pass pointers to the module parameters */

   protoComponentThread = new ProtoComponentThread(&imageIn, &thresholdIn, &imageOut, &statisticsOut, &thresholdValue);

   /* now start the thread to do the work */

   protoComponentThread->start(); // this calls threadInit() and it if returns true, it then calls run()

Graceful Shut-down

To achieve clean shutdown, two RFModule methods, yarp::os::RFModule::interruptModule() and yarp::os::RFModule::close(), should be overridden.

The interruptModule() method will be called when it is desired that updateModule() finish up. When it has indeed finished, close() will be called.

The interruptModule() method should first call the stop() method for the thread (e.g. protoComponentThread->stop();) and then call the interrupt method for each of the ports that it opened in the configure() method. For example:

bool ProtoComponent::interruptModule()
{
   protoComponentThread->stop();

   imageIn.interrupt();
   thresholdIn.interrupt();
   imageOut.interrupt();
   handlerPort.interrupt();

   return true;
}

bool ProtoComponent::close()
{ 
   imageIn.close();
   thresholdIn.close();
   imageOut.close();
   handlerPort.close();

   return true;
} 

The order in which you do this is very important: first stop() the thread, then interrupt() the ports, then close() the ports. Getting this out of sequence causes problems when shutting down a component and it will often hang, requiring you to kill the process.

For yarp::os::RFModule, the method yarp::os::RFModule::updateModule() will be called from the main control thread until it returns false. After that a clean shutdown will be initiated. The period with which it is called is determined by the method yarp::os::RFModule::getPeriod(). Neither method need necessarily be overridden. The default methods provide the required functionality.

/* Called periodically every getPeriod() seconds */

bool ProtoComponent::updateModule()
{
   return true;
}

double ProtoComponent::getPeriod()
{
   /* module periodicity (seconds), called implicitly by protoComponent */
    
   return 0.1;
}

Note that the updateModule() method is not meant to run code that that implements the algorithm encapsulated in the module. Instead updateModule() is meant to be used as a periodic mechanism to check in on the operation of the thread that implements the module (e.g. gather interim statistics, change parameter settings, etc.). The updateModule() is called periodically by the RFModule object, with the period being determined by the getPeriod() method. Both updateModule() and getPeriod() can be overridden in your implementation of myModule.

Component Computation and Communication: the Thread and RateThread Classes

Here we finally explain how to get the component to do some work: the functionality associated with computation and communication. This is defined in the protoComponentComputation.cpp file. This functionality revolves around the Thread and RateThread classes: how to access the parameters passed to it from the derived RFModule object, how to perform some useful work.

Using Threads to Implement Your Algorithm

For the module to actually do anything, it should start or stop threads using the YARP Thread and RateThread classes. Typically, these threads are started and stopped in the configure and close methods of the RFModule class. If you are writing a control loop or an algorithm that requires precise scheduling your should use the RateThread class.

Just as the starting point in writing a component for the CINDY repository is to develop a sub-class of the yarp::os::RFModule class, the starting point for implementing the algorithm within that component is to develop a sub-class of either Thread or RateThread.

In the following, we will explain how to do it with Thread; it's straightforward to extend this to RateThread: effectively, you provide an argument with the RateThread instantiation specifying the period with which the thread should be spawned; the thread just runs once so that you don't have to check isStopping() to see if the thread should end as in the Thread example below.

Perhaps one of the best ways of thinking about this is to view it as a two levels of encapsulation, one with RFModule, and another with Thread; the former deals with the configuration of the module and the latter dealing with the execution of the algorithm. The only tricky part is that somehow these two objects have to communicate with one another.

You need to know three things (two of which we can covered already):

  1. The thread is instantiated and started in the configure() method.
  2. The thread is stopped in the close() method.
  3. When the thread is instantiated, you pass the module parameters to it as a set of arguments (for the constructor).

Let's begin with the definition of a thread ProtoComponentThread (capital P because we are going to create a sub-class) and then turn our attention to how it is used by protoComponent.

An example of how to use the Thread class

First, we define a sub-class, or derived class, of the yarp::os::Thread class. The algorithm's variables - and specifically the thread's parameters and ports - go in the private data members part and you need to override four methods:

  1. ProtoComponentThread::ProtoComponentThread(); // the constructor
  2. bool threadInit(); // initialize variables and return true if successful
  3. void run(); // do the work
  4. void threadRelease(); // close and shut down the thread

There are a number of important points to note.

First, the variables in the ProtoComponentThread class which represent the thread's parameters and port should be pointer types and the constructor parameters should initialize them. In turn, the arguments of the protoComponentThread object instantiation in the configure() should be the addresses of (pointers to) the module parameters and ports in the protoComponentThread object. In this way, the thread's parameter and port variables are just references to the original module parameters and ports that were initialized in the configure method of the protoComponent object.

Second, threadInit() returns true if the initialization was successful, otherwise it should return false. This is significant because if it returns false the thread will not subsequently be run.

Third, the run() method is where the algorithm is implemented. Typically, it will run continuously until some stopping condition is met. This stopping condition should include the return value of a call to the yarp::os::Thread::isStopping() method which flags whether or not the thread is to terminate. In turn, the value of yarp::os::Thread::isStopping() is determined by the yarp::os::Thread::stop() method which, as we saw already, is called in protoComponent.close().

The following is an example declaration and definition of the ProtoComponentThread class taken from protoComponent.h

/** @file protoComponent.h  Interface file for the example CINDY component */
 
#include <yarp/os/Thread.h>
 
using namespace std;
using namespace yarp::os; 
using namespace yarp::sig;
  
class ProtoComponentThread : public Thread {

private:

   /* class variables */

   bool               debug;
   int                x, y;
   PixelRgb           rgbPixel;
   ImageOf<PixelRgb> *image;
   int               *thresholdValue;   
   VectorOf<int>     *thresholdVector;
   int               numberOfForegroundPixels;

   /* thread parameters: they are pointers so that they refer to the original variables in protoComponent */

   BufferedPort<ImageOf<PixelRgb> > *imagePortIn;
   BufferedPort<VectorOf<int> >     *thresholdPortIn; 
   BufferedPort<ImageOf<PixelRgb> > *imagePortOut; 
   BufferedPort<Bottle>             *statisticsPortOut; 
   
  public:
 
    /* class methods */
 
    ProtoComponentThread(BufferedPort<ImageOf<PixelRgb> > *imageIn, 
                         BufferedPort<VectorOf<int> >     *thresholdIn, 
                         BufferedPort<ImageOf<PixelRgb> > *imageOut,
                         BufferedPort<Bottle>             *statisticsOut, 
                         int *threshold );
    bool threadInit();     
    void threadRelease();
    void run(); 
};
/* protoComponentComputation.cpp Implementation file for the computation and communication aspects of protoComponent */

ProtoComponentThread::ProtoComponentThread(BufferedPort<ImageOf<PixelRgb> > *imageIn, 
                                           BufferedPort<VectorOf<int> >     *thresholdIn, 
                                           BufferedPort<ImageOf<PixelRgb> > *imageOut,
                                           BufferedPort<Bottle>             *statisticsOut, 
                                           int *threshold)
{
   imagePortIn       = imageIn;
   thresholdPortIn   = thresholdIn;
   imagePortOut      = imageOut; 
   statisticsPortOut = statisticsOut;
   thresholdValue    = threshold;
}

bool ProtoComponentThread::threadInit() 
{
   /* initialize variables and create data-structures if needed */

   debug = false;

   return true;
} 

void ProtoComponentThread::run(){

   /* 
    * do some work ....
    * for example, convert the input image to a binary image using the threshold provided 
    */ 
   
   unsigned char value;
   double start;
 
   start = yarp::os::Time::now(); // start time

   while (isStopping() != true) { // the thread continues to run until isStopping() returns true
  
      if (debug)
         cout << "protoComponentThread: threshold value is " << *thresholdValue << endl;
      
      /* read image ... block until image is received */

      do {
         image = imagePortIn->read(true);
      } while ((image == NULL) && (isStopping() != true));  // exit loop if shutting down;
      
      if (isStopping()) break; // abort this loop to avoid make sure we don't continue and possibly use NULL images 


      /* read threshold ... block if threshold is not received */
      /*
      do {
         thresholdVector = thresholdPortIn->read(false);
      } while ((thresholdVector == NULL) && (isStopping() != true));  // exit loop if shutting down;
      */
  
      /* read threshold ... do not block if threshold is not received */

      thresholdVector = thresholdPortIn->read(false);
    
      if (thresholdVector != NULL) {
            *thresholdValue = (int) (*thresholdVector)[0];
      }


      if (debug)
         cout << "protoComponentThread: threshold value is " << *thresholdValue << endl;
      

      /* write out the binary image */

      ImageOf<PixelRgb> &binary_image = imagePortOut->prepare();
      binary_image.resize(image->width(),image->height());

      numberOfForegroundPixels = 0;

      for (x=0; x<image->width(); x++) {
         for (y=0; y<image->height(); y++) {

             rgbPixel = image->safePixel(x,y);

             if (((rgbPixel.r + rgbPixel.g + rgbPixel.b)/3) > *thresholdValue) {
                value = (unsigned char) 255;
                numberOfForegroundPixels++;
             }
             else {
                value = (unsigned char) 0;
             }

             rgbPixel.r = value;
             rgbPixel.g = value;
             rgbPixel.b = value;

             binary_image(x,y) = rgbPixel;
          }
       }
       
       imagePortOut->write();

       /* write out the image statistics */

       Bottle &statisticsMessage = statisticsPortOut->prepare();

       statisticsMessage.clear();

       statisticsMessage.addInt((int)(yarp::os::Time::now()-start));
       statisticsMessage.addString("seconds elapsed");
       statisticsMessage.addString(" - foreground pixel count is");
       statisticsMessage.addInt(numberOfForegroundPixels);
       statisticsPortOut->write();
   }
}

void ProtoComponentThread::threadRelease() 
{
   /* for example, delete dynamically created data-structures */
}

GUI Component Computation and Communication: the FLTK and guiUtilities Libraries

This section explains how you can write your own graphic user interface (GUI). We will use the specific example of a GUI for the protoComponent component. This will be implemented as a separate stand-along component protoComponentGUI.

The functionality associated with configuration and coordination, i.e. with the protoComponentGUIConfiguration.cpp and protoComponentGUI.h files, is essentially the same as for the protoComponent example so we will skip over that part. For reference, you can see the complete source code in The protoComponentGUI Example.

Here we address the functionality associated with computation and communication, i.e. with the protoComponentGUIComputation.cpp and protoComponent.h files (also included in The protoComponentGUI Example). As with protoComponent, the functionality revolves around the Thread and RateThread classes but the difference here is that the ProtoComponentGUIThread::run() now contains code to implement the GUI using the FLTK and guiUtilities libraries. That is the essential difference.

First, we look at the definition of the ProtoComponentGUIThread. The only thing worthy of note here is the use of the inclusion of the guiUtilities.h file to allow us use the guiUtilities library. This library, which is included in the CINDY release software repository, provide a number of general-purpose classes and methods to lighten the burden of writing a GUI. In particular, here we see the definition of the two images DVimage *rgbDVImage; and DVimage *binaryDVImage;. The DVimage is one of the utility classes in the guiUtilities library. Other classes, which we will see later, include the DVdisplay class with is a specially-design GUI widget that allows the display of DVimage image objects.

/** @file protoComponentGUI.h  Interface file for the example CINDY component */

#include <iostream>
#include <string>

#include <yarp/sig/all.h>
#include <yarp/os/all.h>
#include <yarp/os/RFModule.h>
#include <yarp/os/Network.h>
#include <yarp/os/Thread.h>
 
#include "guiUtilities.h"

using namespace std;
using namespace yarp::os; 
using namespace yarp::sig;
  
#define STRINGLENGTH 132 // used to define a string when post-processing the bottle messages

class ProtoComponentGUIThread : public Thread {

private:

  /* class variables */

   bool              debug;
   int               x, y;
   PixelRgb          rgbPixel;
   int               *thresholdValue;   
   nt               numberOfForegroundPixels;
   int               rgb_width;
   int               rgb_height;
   int               rgb_depth;
   int               binary_width;
   int               binary_height;
   int               binary_depth;
   unsigned char     pixel_value;
   float             float_pixel_value;
   double            thresholdValueDouble;
   string            logoFilenameValue;
   int               temp;
 
   ImageOf<PixelRgb> *rgbYARPImage;
   ImageOf<PixelRgb> *binaryYARPImage;
   DVimage           *rgbDVImage;
   DVimage           *binaryDVImage;
   Bottle            *statisticsMessage; 

   /* thread parameters: they are pointers so that they refer to the original variables in protoComponentGUI */

   BufferedPort<ImageOf<PixelRgb> > *colourImagePortIn;
   BufferedPort<ImageOf<PixelRgb> > *binaryImagePortIn;
   BufferedPort<Bottle>             *statisticsPortIn; 
   BufferedPort<VectorOf<int> >     *thresholdPortOut; 

public:

   /* class methods */

   ProtoComponentGUIThread(BufferedPort<ImageOf<PixelRgb> > *colourImageIn, 
                           BufferedPort<ImageOf<PixelRgb> > *binaryImageIn,
                           BufferedPort<Bottle>             *statisticsIn, 
                           BufferedPort<VectorOf<int> >     *thresholdOut, 
                           int *threshold, 
                           string logoFilename);
   bool threadInit();     
   void threadRelease();
   void run(); 
};

Note that the thread parameter list contains a filename. This is the name of the file that contain the CINDY logo. We pass it as a parameter from the RFModule::configure() so that we can user the resource finder to locate the file and its path.


Next, we look at the definition of the GUI itself in the run() method. For convenience, we will only show code snippets; refer to The protoComponentGUI Example for the complete source code listing.

The first thing to notice is the instantiation of a number of objects from FLTK classes Fl_Group, Fl_Box, and Fl_PNG_Image. These define a group of widgets, a variety of individual widget, and an image with the CINDY logo.

/* protoComponentGUIComputation.cpp  Implementation file for the example CINDY component */

void ProtoComponentGUIThread::run(){

   Fl_Group *start_protoComponent_GUI;
   Fl_Box *box1, *box2, *heading;
   Fl_PNG_Image *logo=new Fl_PNG_Image(logoFilenameValue.c_str());
 

The next thing is the long list of variables that determine the presentation of the GUI. These are then initialized in as subsequent section. This may look tedious but it means that it is very easy to re-design the layout of the GUI.

   int i, j;
   char modifiedString[STRINGLENGTH]; 

   /* variable that determine the presentation of the GUI */ 

   int control_panel_x, control_panel_y;
   int control_panel_width, control_panel_height;
   int heading_x, heading_y, heading_width, heading_height;
   int display_width, display_height;
   int display_x1, display_x2, display_y;
   int display_spacing;
   int display_offset_x, display_offset_y;
   int control_offset_x, control_offset_y;
   int button_size_x, button_size_y, button_spacing_y;
   int input_size_x, input_size_y;
   int title_height;
   int threshold_x, threshold_y;
   int threshold_size_x, threshold_size_y;
   int section_spacing_y;
   int window_width, window_height, border_width, border_height;
   int text_output_width,text_output_height;
   int text_output_x,   text_output_y;
	
   /* intialize the presentation settings */

   window_width  = GetSystemMetrics(SM_CXFULLSCREEN);      // this is the area available for the window on the screen
   window_height = GetSystemMetrics(SM_CYFULLSCREEN);

   border_width  = GetSystemMetrics(SM_CXSIZEFRAME);  
   border_height = GetSystemMetrics(SM_CYSIZEFRAME);

   display_width  = DISPLAY_WIDTH;   
   display_height = DISPLAY_HEIGHT;
   display_spacing = 25;

   heading_x = (window_width - display_width*2 - display_spacing)/2; 
   heading_y = MENUBAR_HEIGHT;
   heading_width = display_width*2 + display_spacing;       // centre over displays
   heading_height = HEADING_HEIGHT*2;                       // logo and caption

   display_offset_x = heading_x ;
   display_offset_y = heading_y + heading_height;
   display_x1 = display_offset_x;
   display_x2 = display_x1 + display_spacing + display_width  ;
   display_y  = display_offset_y;
  
   title_height = 12;

   button_size_x = 130;
   button_size_y = 20;
   button_spacing_y = 5;

   input_size_x = button_size_x;
   input_size_y = button_size_y;
 
   control_offset_x = 20;
   control_offset_y = 0;

   control_panel_width  = display_width * 1;
   control_panel_height = display_height / 2; // alternative to match the panel height to the number of widgets: 
                                              // control_panel_height = title_height + 1*(5 + button_size_y) + title_height; 
   control_panel_x = display_x2;
   control_panel_y = display_y + display_height + display_spacing;

   section_spacing_y = 8;

   threshold_size_x = control_panel_width - 2 * control_offset_x;
   threshold_size_y = input_size_y;
   threshold_x = control_panel_x + control_offset_x;
   threshold_y = control_panel_y + control_offset_x + 0 * (button_size_y + button_spacing_y); // 0 because threshold is the first widget in the control panel
                                                                                              // increase by 1 for every extra widget added
   text_output_width  = display_width;
   text_output_height = display_height / 2;
   text_output_x = display_offset_x;
   text_output_y = display_offset_y + display_height + display_spacing;
 

With that done, we can then define a group with all the GUI widgets and add the widgets to this group, one by one.

   /* define a group with all the GUI widgets */

   start_protoComponent_GUI = new Fl_Group(0,MENUBAR_HEIGHT,window_width,window_height-MENUBAR_HEIGHT,"");

   start_protoComponent_GUI->begin();  

      /*  ... note: we don't declare heading because it is declared in the guiUtilities library   */ 

      heading = new Fl_Box(heading_x, heading_y,
                           heading_width,heading_height,"The protoComponentGUI Example" );

      heading->align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER |  FL_ALIGN_IMAGE_OVER_TEXT);
      heading->labelsize(20);
      heading->labelcolor(FL_BLACK);  
      heading->labelfont(FL_HELVETICA_BOLD);
      heading->box(FL_NO_BOX);
      heading->image(logo);
  
      /* boxes to frame images ... note: we don't declare box1 or box2 because they are declared in the guiUtilities library   */ 
 
      box1 = new Fl_Box(display_x1-BORDER,display_y-BORDER,
                        display_width+2*BORDER,display_height+2*BORDER,"" );
      box1->box(FL_DOWN_BOX);
      box1->align(FL_ALIGN_BOTTOM | FL_ALIGN_CENTER);
      box1->labelsize(12);
 
      box2 = new Fl_Box(display_x2-BORDER,display_y-BORDER,
                        display_width+2*BORDER,display_height+2*BORDER,"" );
      box2->box(FL_DOWN_BOX);
      box2->align(FL_ALIGN_BOTTOM | FL_ALIGN_CENTER);
      box2->labelsize(12);
 
      /* image display ... note: we don't declare display1 or display2 because they declared in the guiUtilities library   */ 
      
      display1 = new DVdisplay(display_x1, display_y, 
	                            display_width,display_height);

      display2 = new DVdisplay(display_x2, display_y, 
   	                         display_width,display_height);

      /* box to frame controls */

      Fl_Box *control_panel;
      control_panel = new Fl_Box(control_panel_x, control_panel_y, control_panel_width, control_panel_height,"" );
      control_panel->align(FL_ALIGN_TOP | FL_ALIGN_CENTER | FL_ALIGN_INSIDE);
      control_panel->labelsize(12);
      control_panel->labelfont(FL_HELVETICA_BOLD);
      control_panel->box(FL_PLASTIC_DOWN_BOX); 

      /* threshold slider */

      Fl_Value_Slider *threshold;
      threshold = new Fl_Value_Slider(threshold_x, threshold_y, threshold_size_x, threshold_size_y,"Binary Threshold Value");
      threshold->type(FL_HOR_NICE_SLIDER);
      threshold->textsize(11);
      threshold->callback(valuator_cb, &thresholdValueDouble); // NB valuator_cb() is a general-purpose callback defined in guiUtilities.h
      threshold->labelsize(12);                                // other general-purpose callbacks are defined there too, e.g. radio buttons
      threshold->labelfont(FL_HELVETICA_BOLD);                 // some widgets may require you to write your own callback
      threshold->when(FL_WHEN_ENTER_KEY | FL_WHEN_CHANGED | FL_WHEN_RELEASE); 
      threshold->align(FL_ALIGN_TOP);
      threshold->minimum(0);
      threshold->maximum(255);
      threshold->step(1);
      threshold->value((double)*thresholdValue);  // initialize the threshold to the value passed as a parameter
      threshold->box(FL_PLASTIC_DOWN_BOX);
 
      /* Text output ... note: we don't declare text_output because it is declared in the guiUtilities library   */ 
 
      text_output = new Fl_Multiline_Output(text_output_x, text_output_y, text_output_width, text_output_height,"" );
      text_output->align(FL_ALIGN_TOP | FL_ALIGN_CENTER );
      text_output->labelsize(12);
      text_output->textsize(12);
      //text_output->color(FL_GREEN);
      text_output->value("");
      //text_output->box(FL_THIN_DOWN_FRAME);  // matches the image display frames
      text_output->box(FL_PLASTIC_DOWN_BOX);   // rounded edges for something more visually appealing
 
   start_protoComponent_GUI->end();  // end of the group 

Now we are in a position to actually create the GUI. We do this by instantiating a window class Fl_Double_Window, position it, enable double buffering to make images in video sequences transition smoothly, display the window, add the group of GUI widgets, and then redraw the window. We call the FLTK function Fl::check(); to display the window.

   // create main window
  
   DVwindow = new Fl_Double_Window(window_width-border_width,window_height-border_height,"The protoComponentGUI Example");
   DVwindow->position(0,0); 
	
   Fl::visual(FL_DOUBLE|FL_INDEX); // enable double buffering of the window 

   DVwindow->end(); 
   DVwindow->show();

   // add the GUI

   DVwindow->add(start_protoComponent_GUI);
   DVwindow->redraw();
   Fl::check();

We can now interact with the widgets. First we display some text in the text_output widget using the message() function. This function is one of the utilities that is provided by the guiUtilities library.

Having done that, we are done with the GUI definition. We now revert to the normal YARP thread loop. Notice however, that we include two FLTK method calls inside this loop, one to redraw the window and one the tell FLTK that the window has been re-drawn and needs to be redisplayed.

   /* write some text in the window ...                                                               */
   /* note that function message() is defined in guiUtilities as a general-purpose routine to write    */
   /* to the predefined display widget text_output ... notice how we didn't declare text_output above */
   /* we didn't have to because it is declared in guiUtilities                                        */

   message("Waiting to start .... image statistics will be displayed here");


   /*************************************************************************************/
   /*   This is where the definition of the GUI ends and the normal run() loop begins   */
   /*************************************************************************************/

   while (isStopping() != true) { // the thread continues to run until isStopping() returns true
 
      DVwindow->redraw();

      Fl::check();         // refresh the GUI   .... we do it this way rather than calling Fl::run() as we nomally would 
                            // because we do not want to cede control to the event loop 

Further down this loop we have occasion to interact with the FLTK widgets, e.g. to read an image from a port, copy it to the local format suitable for display, and then display it.

      /*** read colour image ... do not block if image is not received ***/

      rgbYARPImage = colourImagePortIn->read(false);

      if (rgbYARPImage != NULL) {

         rgb_width  = rgbYARPImage->width();  
         rgb_height = rgbYARPImage->height();
         rgb_depth  = 3;
    
         if (debug) printf("protoComponentGUI: rgb width = %d, rgb height = %d, rgb depth = %d\n",rgb_width, rgb_height, rgb_depth);
 
         if (rgbDVImage == NULL) {
             rgbDVImage = new DVimage(rgb_width, rgb_height, rgb_depth);
         }


         /*  now copy the image to local format */
 
         for (x = 0; x < rgb_width; x++) {
            for (y = 0; y < rgb_height; y++) {
               rgbPixel = rgbYARPImage->safePixel(x,y);  
               rgbDVImage->put_pixel(x, y, rgbPixel.r, 0);
               rgbDVImage->put_pixel(x, y, rgbPixel.g, 1);
               rgbDVImage->put_pixel(x, y, rgbPixel.b, 2);
           }
         } 
 
         display1->draw(rgbDVImage); 
      }
      else {
         if (debug) printf("protoComponentGUI: colour image not received\n");
      }

We also read the image statistics from another port, process them, and then display them in a text box.

      /* read the image statistics ... do not block if bottle is not received*/

      statisticsMessage = statisticsPortIn->read(false);
     
      if (statisticsMessage != NULL) {

         /* for some strange reason, YARP puts double quotes around every individual string in a bottle so we strip them here */

         j=0;
         for (i=0; i<min(STRINGLENGTH-1,(int)strlen(statisticsMessage->toString().c_str()));i++) {
            if (statisticsMessage->toString().c_str()[i]!='\"') {
               modifiedString[j] = statisticsMessage->toString().c_str()[i];
               j++; 
            }
         }
         modifiedString[j]='\0';


         /* now copy the message to the display */

         message(modifiedString);
         if (debug) cout << "protoComponentGUIThread: statistics message is " << modifiedString << endl;    
      }
      else {
         if (debug) printf("protoComponentGUI: statistics not received\n");
      }

Finally, we can use the threshold value set by the FLTK valuator and send it on a port (to protoComponent).

      /*** write the threshold ***/

      VectorOf<int> &thresholdVector = thresholdPortOut->prepare(); 
      thresholdVector.resize(1);
      thresholdVector(0) = *thresholdValue;
 
      thresholdPortOut->write();

Test Applications

As we noted at the outset, in a Component-Based Software Engineering (CBSE) project, such as CINDY, the source code application file is replaced by the application script file or application XML file that runs the various components and connects them together in a working system. Thus, CINDY applications, i.e. collections of inter-connected YARP modules, are described in XML and launched using a utility called gyarpmanager. Refer to the Software Users Guide for more details on how to run these application descriptions.

In this section, we provide two test applications.

The first test application shows how to configure and run a simple application to use the protoComponent by connecting it to other components that provide input images and display the output images. This application uses yarpview modules to view the images. The threshold is modified online by sending commands to protoComponent from the command line in a terminal window.

The second test application shows how to configure and run a simple application to use protoComponent and protoComponentGUI together. In this case, the images are displayed in the GUI rather than yarpview displays and the threshold is modified interactively using the GUI controls.

Both applications have some some command-line parameters for illustration. Remember that these command-line parameter values have priority over the same parameter values specified in the relevant configuration file, which in turn have priority over the default values provided in the source code.

<application>
<name>Demo of protoComponent</name>

<dependencies>
   <port>/robot/cam/left</port>
</dependencies>

<module>
   <name>protoComponent</name>
   <parameters>--context components/protoComponent/config </parameters>
   <node>cindy1</node>
   <tag>protoComponent</tag>
</module>

<module>
   <name>imageSource</name>
   <parameters>--context components/imageSource/config</parameters>
   <node>cindy1</node>
   <tag>imageSource</tag>
</module>

<module>
   <name>yarpview</name>
   <parameters>--name /inputImage --x 000 --y 000 --w 320 --h 318 </parameters>
    <node>cindy1</node>
   <tag>input_image</tag>
</module>

<module>
   <name>yarpview</name>
   <parameters>--name /binaryImage --x 320 --y 000 --w 320 --h 318 </parameters>
   <node>cindy1</node>
   <tag>plot_image</tag>
</module>

<connection>
  <from>/robot/cam/left</from>
  <to>/inputImage</to>
  <protocol>tcp</protocol>
</connection>

<connection>
  <from>/robot/cam/left</from>
  <to>/protoComponent/image:i</to>
  <protocol>tcp</protocol>
</connection>

<connection>
  <from>/protoComponent/image:o</from>
  <to>/binaryImage</to>
  <protocol>tcp</protocol>
</connection>

</application>
<application>
<name>Demo of protoComponentGUI</name>

<dependencies>
   <port>/robot/cam/left</port>
</dependencies>

<module>
   <name>protoComponentGUI</name>
   <parameters>--context components/protoComponentGUI/config </parameters>
   <node>cindy1</node>
   <tag>protoComponentGUI</tag>
</module>

<module>
   <name>protoComponent</name>
   <parameters>--context components/protoComponent/config </parameters>
   <node>cindy1</node>
   <tag>protoComponent</tag>
</module>

<module>
   <name>imageSource</name> 
   <parameters>--context components/imageSource/config --width 640 --height 480 </parameters>
   <node>cindy1</node>
   <tag>imageSource</tag>
</module>

<connection>
  <from>/robot/cam/left</from>
  <to>/protoComponent/image:i</to>
  <protocol>tcp</protocol>
</connection>

<connection>
  <from>/protoComponent/image:o</from>
  <to>/protoComponentGUI/binaryimage:i</to>
  <protocol>tcp</protocol>
</connection>

<connection>
  <from>/protoComponent/statistics:o</from>
  <to>/protoComponentGUI/statistics:i</to>
  <protocol>tcp</protocol>
</connection>

<connection>
  <from>/robot/cam/left</from>
  <to>/protoComponentGUI/colourimage:i</to>
  <protocol>tcp</protocol>
</connection>

<connection>
  <from>/protoComponentGUI/threshold:o</from>
  <to>/protoComponent/threshold:i</to>
  <protocol>tcp</protocol>
</connection>

</application>

To run the application, follow the instruction in the Software Users Guide.

Software Engineering Standards

Finally, note that CINDY follows a set of recommended software engineering standardi, as follows.

Please take the time to read through these documents.



Return to The CINDY Cognitive Architecture main page.