Copyright © 2006,2007,2008,2009 Peter Soetens, FMTC
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation, with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of this license can be found at http://www.fsf.org/copyleft/fdl.html.
Table of Contents
This document describes the Orocos OCL::ReportingComponent for monitoring and capturing data exchanged between Orocos components.
Each Orocos component can have one or more data ports. One can configure the reporting components such that one or more ports are captured of one or more peer components. The sample rate and the file format can be selected.
A common usage scenario of the OCL::ReportingComponent goes as follows. An Orocos application is created which contains a reporting component and various other components. The reporting component is peer-connected to all components which must be monitored. An XML file or script command defines which data ports to log. When the reporting component is started, it reads the ports and writes the exchanged data to a file at a given sample rate.
One can not use the OCL::ReportingComponent directly but must use a derived component which implements the method of writing out the data. There exists two variants: OCL::FileReporting for writing data to a file and OCL::ConsoleReporting which prints the data directly to the screen. These two examples can aid you in writing your own data format or to transfer data over a network connection.
The OCL::ReportingComponent is configured using a single XML file which sets the component's properties and describes which components and ports to monitor.
In order to report data of other components, they must be added as a Peer to the reporting component. The following C++ setup code does this for the example above (Figure 1, “Component Reporting Example”):
#include <ocl/FileReporting.hpp> // ... OCL::FileReporting reporter("Reporter"); Controller controller("Controller"); Plant plant("Plant"); Camera cam0("Camera"); reporter.addPeer( &controller ); reporter.addPeer( &camera ); controller.addPeer( &plant );
Alternatively, if you use the Deployer, you might add this listing to your application XML file, instead of using the hard-coded C++ setup above:
<simple name="Import" type="string"><value>/usr/lib/liborocos-reporting</value></simple> <struct name="Reporter" type="OCL::FileReporting"> <struct name="Activity" type="PeriodicActivity"> <simple name="Period" type="double"><value>0.01</value></simple> <simple name="Priority" type="short"><value>0</value></simple> <simple name="Scheduler" type="string"><value>ORO_SCHED_OTHER</value></simple> </struct> <simple name="AutoConf" type="boolean"><value>1</value></simple> <simple name="AutoStart" type="boolean"><value>0</value></simple> <simple name="AutoSave" type="boolean"><value>1</value></simple> <simple name="LoadProperties" type="string"><value>reporting.cpf</value></simple> <!-- List all peers (uni-directional) --> <struct name="Peers" type="PropertyBag"> <simple type="string"><value>Controller</value></simple> <simple type="string"><value>Camera</value></simple> </struct>
Note that the AutoSave flag is turned on (this is optional) to save the settings when the Reporter component is cleaned up by the Deployer.
This is an example property file:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "cpf.dtd"> <properties> <simple name="AutoTrigger" type="boolean"><description>When set to 1, the data is taken upon each update(), otherwise, the data is only taken when the user invokes 'snapshot()'.</description><value>1</value></simple> <simple name="WriteHeader" type="boolean"><description>Set to true to start each report with a header.</description><value>1</value></simple> <simple name="Decompose" type="boolean"><description>Set to true to decompose data ports.</description><value>1</value></simple> <simple name="ReportFile" type="string"><description>Location on disc to store the reports.</description><value>reports.dat</value></simple> <simple name="Synchronize" type="boolean"><description>Set to true if the timestamp should be synchronized with the logging</description><value>0</value></simple> <struct name="ReportData" type="PropertyBag"> <description>A PropertyBag which defines which ports or components to report.</description> <simple name="Component" type="string"><value>Camera</value></simple> <simple name="Port" type="string"><value>Controller.SensorValues</value></simple> <simple name="Port" type="string"><value>Controller.SteeringSignals</value></simple> </struct> </properties>
The AutoTrigger
property toggles if the data is captured
at the time a new line is written to file or at a user determined time.
If AutoTrigger
is set to false, a data snapshot is taken
when the user invokes the snapshot()
method of the
ReportingComponent.
If WriteHeader
is set to true, a header will be written
describing the file format layout.
If Decompose
is set to true, complex data on ports will
be decomposed into separate table columns. Otherwise, each port appears as one
column.
The ReportData
struct describes the ports to monitor.
As the example shows (see also Figure 1, “Component Reporting Example”),
a complete component can be monitored (Camera) or specific ports of
a peer component can be monitored. The reporting component can monitor
any data type as long as it is known in the Orocos type system. Extending
the type system is explained in the Plugin Manual of the Real-Time Toolkit.
The property file of the reporting component must be read with the loadProperties script method:
marshalling.loadProperties("reporting.cpf")
You can not use readProperties()
because only
loadProperties
loads your ReportData
struct into the
ReportingComponent.
With
marshalling.writeProperties("reporting.cpf")
, the current configuration can be written to disk again.
The scripting commands of the reporting components can be listed using the this command on the TaskBrowser. Below is a snippet of the output:
Method : bool reportComponent( string const& Component ) Add a Component for reporting. Only works if Component is connected. Component : Name of the Component Method : bool reportData( string const& Component, string const& DataObject ) Add a Component's DataSource for reporting. Only works if DataObject exists and Component is connected. Component : Name of the Component DataObject : Name of the DataObject. For example, a property or attribute. Method : bool reportPort( string const& Component, string const& Port ) Add a Component's Connection or Port for reporting. Component : Name of the Component Port : Name of the Port to the connection. Method : bool screenComponent( string const& Component ) Display the variables and ports of a Component. Component : Name of the Component Method : void snapshot( ) Take a new shapshot of the data and set the timestamp. Method : bool unreportComponent( string const& Component ) Remove a Component from reporting. Component : Name of the Component Method : bool unreportData( string const& Component, string const& DataObject ) Remove a DataObject from reporting. Component : Name of the Component DataObject : Name of the DataObject. Method : bool unreportPort( string const& Component, string const& Port ) Remove a Connection for reporting. Component : Name of the Component Port : Name of the Port to the connection.