How to program your own application using Hugr framework?

:!: DEPRECATED Information

This document explains how to use the Hugr framework to program your own applications.

Hugr Principles

The Hugr framework is a middleware library providing tools for applications to share information by simply reading and writing data-objects addressed by means of an application-defined name and a key.In some aspects, Hugr framework is related to OMG DDS (data distribution service) standard.

It is based on shared memory map called store where data are to be written or read by applications. Each application must register the data it wants to share on the store.

Then the data are available for other processes to be read or to be set accessing to the store.

Hugr store supports any kind of data type: basic ones as integer, double, boolean, float, std::string but also object type as long as primitives for handling the data type are available.

Here is two UML communication (or collaboration) diagrams, summarizing typicals applications in CycabTK. Click on the thumbnail to see the details. UML collaboration diagrams

As you can see, the behaviour of your application will be strictly the same in both simulation or real tests. This is one of the main advantages to use shared memory services like Hugr for data exchange.

Application using Hugr Framework skeleton

  1. Declare a Hugr Store object using the constructor :
    hugr::Store
  2. Get a pointer to the store using the method :
    hugr::connect()
  3. Register/allocate variables in the Hugr store using the method :
    hugr::registerVariable(variable_name_string, variable_type)
  4. Retrieve variable identifier relative to the variable in the Hugr store using the method :
    hugr::VariableId hugr::lookupVariable(variable_name_string)
  5. Get variable value using the method :
    hugr::readVariable(hur::VariableId, variable_type)
  6. Set variable value and update the Hugr store consequently using the method :
    hugr::writeVariable(hugr::VariableId, variable_type)
  7. Check the content of the Hugr store : using the hugr web interface, the hugr shell interface (cf Hugr user page)

Some Application Examples

  • Application that registers a integer variable set to 42 and updates it to 12.
#include <iostream>
#include "hugr.hpp"
using namespace std; 
using namespace hugr; 
 
int main()
{ 
        try { 
                Store store; //(1)
                int v1 = 42;
                VariableId id1;
                store.connect(); // (2)
                store.registerVariable("variable1", v1); // (3)
                id1 = store.lookupVariable("variable1"); // (4)
                sleep(2); v1 = 12;
                store.writeVariable(id1, v1); // (6)
        }
        catch(const exception &amp;e) {
                cout << "Writer: " << e.what() << endl;
        }
        return 0;
} 
  • Application that retrieves a integer variable from the store.
#include <iostream>
#include "hugr.hpp"
using namespace std; 
using namespace hugr; 
 
int main()
{ 
        try { 
                Store store; // (1)
                int v = 0;
                VariableId id;
                store.connect(); //(2)
                sleep(1);
                id = store.lookupVariable("variable1"); // (4)
                store.readVariable(id, v); // (5)
                cout << "variable1 found at id: " << id << " value=" << v << endl; 
        }
        catch(const exception &amp;e) {
                cout << "Reader: " << e.what() << endl;
        }
        return 0;
}

How to handle complex objects in the Hugr store

Hugr framework implementation uses Boost serialization library (Boost provides free peer-reviewed portable C++ source libraries).

Serialization means the reversible deconstruction of an arbitrary set of C++ data structures to a sequence of bytes. This might be used to implement object persistence, remote parameter passing or other facility. Boost library uses the term “archive” to refer to a specific rendering of this stream of bytes. This could be a file of binary data, text data, XML, or some other created by the user of this library. So serialization can be seen as the mecanism for loading/saving data structures into a specific stream.

With respect to Hugr, the “archive” refers to the buffer used to load/save data into Hugr sharing memory.

Accordingly to the Boost serialization library API, to handle complex objects in the Hugr store, you will need to implement the following methods for your own complex objects :

  • the method serialize, if the “load/save” operations are similar, performed in the same sequence, see definition :
template<class Archive> void serialize(Archive & ar, const unsigned int version)
;
  • the method load, save if the “load/save” operations are not similar so serialize method needs to be split, see definitions above :
template<class Archive> void load(Archive & ar, const unsigned int version);
template<class Archive> void save(Archive & ar, const unsigned int version);
BOOST_SERIALIZATION_SPLIT_MEMBER()

Here are two examples illustrating the use of these methods :

  • using similar load/save operations :
// include headers that implement a archive in simple text format
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
 
class gps_position
{
private:
    friend class boost::serialization::access;
    // When the class Archive corresponds to an output archive, the
    // & operator is defined similar to <<.  Likewise, when the class Archive
    // is a type of input archive the & operator is defined similar to >>.
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & degrees;
        ar & minutes;
    }
    int degrees;
    int minutes;
public:
    gps_position(){};
    gps_position(int d, int m) : degrees(d), minutes(m) {}
};
  • using different load/save operations :
#include <boost/serialization/list.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/version.hpp>
#include <boost/serialization/split_member.hpp>
 
class gps_position
{
    friend class boost::serialization::access;
    template<class Archive>
    void save(Archive & ar, const unsigned int version) const
    {
        // note, version is always the latest when saving
        ar & degrees;
        ar & minutes;
        ar & seconds;
    }
    template<class Archive>
    void load(Archive & ar, const unsigned int version)
    {
        ar & degrees;
        ar & minutes;
        if(version > 0)
            ar & seconds;
    }
    BOOST_SERIALIZATION_SPLIT_MEMBER()
public:
    gps_position(){};
    gps_position(int d, int m, float s) : degrees(d), minutes(m), seconds(s) {}
};
 
BOOST_CLASS_VERSION(gps_position, 1)

Here is a program illustrating how to use gps_position object with Hugr.

int main() {
    // Create the Hugr store
    Store store;
    gps_position gps(35, 59, 24.567f);
 
    store.connect();
    try
    {
        store.registerVariable("gps_position", gps);
    }
    catch(const std::runtime_error &e)
    {
        // Save gps_position to archive ie store
        store.writeVariable(store.lookupVariable("gps_position"), gps);
    }
    return 0;
}

Till now we present an intrusive way of handling serialization. But Boost serialization can be handled in a non-intrusive way. The main application to non-intrusive serialization is to permit serialization to be implemented for classes without changing the class definition. In order for this to be possible, the class must expose enough information to reconstruct the class state.

This is usefull for instance if you want to use objects as OpenCV IplImage whose definition you can not change. Here is an example on how to write a the serialize mechanism for the IplImage class and how to use it in a Hugr store.

#include <opencv/cv.h>
#include <opencv/cxcore.h>
 
#include <fstream>
#include <iostream>
 
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/split_free.hpp>
#include <boost/serialization/export.hpp>
 
 
using namespace std;
using namespace boost::archive;
 
namespace boost
{
namespace serialization
{
/**
* Serialization for IplImage.
* Variables that are assigned to NULL are the ones ignored by OpenCV
* (but used in Intel Ipl Image Library)
*/
template<class Archive>
void save(Archive & ar, const IplImage & image, const unsigned int version)
{
        ar & image.nSize;
        ar & image.ID;
        ar & image.nChannels;
        ar & image.depth;
        ar & image.dataOrder;
        ar & image.origin;
        ar & image.width;
        ar & image.height;
 
        ar & image.imageSize;
 
        for(int i=0; i<image.imageSize ; i++)
                ar & image.imageData[i];
 
        ar & image.widthStep;
}
 
template<class Archive>
void load(Archive & ar, IplImage & image, const unsigned int version)
{
        int old_size = image.imageSize;
 
        ar & image.nSize;
        ar & image.ID;
        ar & image.nChannels;
        ar & image.depth;
        ar & image.dataOrder;
        ar & image.origin;
        ar & image.width;
        ar & image.height;
 
        image.roi = NULL;
        image.maskROI = NULL;
 
        ar & image.imageSize;
       if(image.imageSize != old_size)
        {
                delete image.imageData;
                image.imageData = new char[image.imageSize];
        }
 
        for(int i=0; i<image.imageSize ; i++)
        {
                ar & image.imageData[i];
        }
 
        ar & image.widthStep;
 
        bzero(image.BorderMode, 4);
        bzero(image.BorderConst, 4);
 
        image.imageDataOrigin = image.imageData;
}
} // namespace boost
} // namespace serialization
 
BOOST_CLASS_EXPORT_GUID(IplImage, "IplImage")
BOOST_SERIALIZATION_SPLIT_FREE(IplImage)

Here is a program illustrating how to use IplImage object with Hugr.

int main(int argc, char **argv)
{
        Store store;
        IplImage *image;
 
        if(argc == 2)
        {
                image = cvLoadImage(argv[1]);
        }
        else
        {
                cout << "Usage: " << argv[0] << " filename" << endl;
 
                return 0;
        }
 
        store.connect();
 
        try
        {
                store.registerVariable("image", *image);
        }
        catch(const std::runtime_error &e)
        {
                store.writeVariable(store.lookupVariable("image"), *image);
        }
 
        return 0;
}
Links to the reference manual to be provided….
deprecated/howto/devel-hugr.txt · Last modified: 2012/01/24 15:44 by arias
Recent changes RSS feed Creative Commons License Donate Minima Template by Wikidesign Driven by DokuWiki