This is a very short introduction into a couple of concepts of C++. It should enable a beginner without knowledge in C++ to properly use EEROS in an own simple application.
With namespaces you can group entities such as classes or enums under a choosen name. In this way the global scope can be split into subscopes with distinguished names. EEROS heavely uses namespaces.
In order to use declarations from these namespaces we can either import such a namespace or use the scope operator '::'. Let's look at an example.
using namespace eeros::logger; int main(int argc, char **argv) { StreamLogWriter w(std::cout); Logger<LogWriter>::setDefaultWriter(&w); Logger<LogWriter> log; eeros::control::Constant<std::array<double,4>> c1; using eeros::control::Gain; Gain<> g1; }
With 'using namespace eeros::logger' all the declarations in this namespace are made visible and can be directly used.
The block 'Const' within the namespace 'eeros::control' is used with the aid of the scope operator.
The block 'Gain' within the namespace 'eeros::control' is made available by 'using eeros::control::Gain;' and can be referred to further on without qualifying with the namespace.
Constructors - as any other function - can be overloaded. Many blocks you may want to use in your control system can be instantiated in various ways. Let us consider an example with a Gain
block.
using namespace eeros::control; int main(int argc, char **argv) { Gain<> g1(10); Gain<> g2; g2.setGain(10); }
The first constructor initializes a gain block and sets its gain value to 10. The second instance of the same block is created with a gain value defaulting to 1. This value could then be subsequently set to 10.
Function and class templates are widely used within the eeros framework. Templates allow the parametrization of many blocks and signals. This should be demonstrated with the example of a Constant
block. Such a block should be able to contain a single constant value of any type. It should also be able to hold a multidimensional value.
using namespace eeros::control; using namespace eeros::math; int main(int argc, char **argv) { Constant<> c1(2.5); // type double Constant<int16_t> c2(10); // type int16_t Constant<Matrix<2,1>> c3({2,1.5}); // type Matrix c1.run(); log.info() << c1.getOut().getSignal().getValue(); }
The square brackets - even if left empty - are necessary, because a Constant
block requires a signal type for its output. The block is instantiated per default with a value of type double
. The second declaration chooses a different type. The third declaration uses a type different from an arithmetic type. The type Matrix
is a built-in type which itself can be parametrized with its dimensions.
Do not forget to call the method run
. Without this value of the block is not written to its output signal.
A lambda is an anonymous function which can be passed as a parameter. While using EEROS lambda functions are useful for several cases.
A lambda function must be defined as follows
[captures] (params) {body}
Captures are variables which are defined in the scope where the lambda function is defined and which can be made available to the lambda function either by value or by reference. Params are parameters which can be passed into the function like regular parameters. The body contains the code which is executed by the function.