Providing a shot with data

Online section / Tutorials / QArm Tutorial / Providing a shot contact | download | sitemap
 

In the previous example we showed how timing information about one shot can be obtained using the ARM instrumentation provided with this tutorial. This example explains how additional data can be provided for each shot. Since each shot differs from another by the force and angle selected by the user these values will be saved with each shot. The way to do this with ARM are so called "metrics". Roughly spoken, metrics describe a "name=value" pair, where the name is provided during transaction definition (i.e. when the QSimpleArmTran object is instantiated) while the value can be changed each time the transaction is started. The metric content can therefore be unique for each transaction instance.

Source code

Modifications to the previous example are marked. The other source files were not touched:

lcdrange.h contains the LCDRange class definition
lcdrange.cpp contains the LCDRange implementation
autoshoottimer.h contains AutoShootTimer class (modified)
cannonfield.h contains the CannonField class definition
cannonfield.cpp contains the CannonField implementation (modified)
gameboard.h contains the GameBoard class definition
gameboard.cpp contains the GameBoard implementation
main.cpp contains MyWidget and main

Line-by-Line walkthrough

cannonfield.cpp

The difference to this file in the last chapter is the way the AutoShootTimer is started. Now the AutoShootTime::start() method is provided with angle and force.

    autoShootTimer->start(5,(int)shootAngle,(int)shootForce);

autoshoottimer.h

The main changes were made in this class. The class has two new attributes

    QSimpleArmNumId *angle;
    QSimpleArmNumId *force;
E x c u r s u s

ARM metrics are numbers that can be provided with a transaction instance. Metrics can be used to serve different purposes:

  • Counters are used to save a value that is incremented while the transaction is running, i.e. the metric value has to be provided while the transaction is started and while it is stopped. An example for a counter is the number of bytes transferred during transaction execution.
  • Gauges differ from counters by their values. These can go up and down and can even be negative. Gauges are used to save values that do not increase monotonically. Conventions regarding gauges are:
    1. The maximum value shall be the biggest value reached between a start() and a successive stop() call.
    2. The minimum value shall be the smallest value reached between a start() and a successive stop() call.
    3. The mean value shall be the mean of all values passed between the start() and the successive stop() call
  • Numeric ids are used to save a value when the transaction is started, e.g. the id of the process executing the transaction.
  • Strings with up to 32 characters are supported as well, but we do not dig into it since strings are better represented by properties

The name of a metric and its specific type have to be bound to an ARM application. There is no limit of how many metrics can be bound to an application but to a specific transaction definition. When a transaction is defined it has to be decided which of the metrics are registered to that transaction definition and a so called slot (a number from 0 to 6) is used as identification for that metric. Later when the transaction is started (the transaction instance is created) the slots can be filled with values. Therefore each transaction instance can serve up to 7 different metrics with a type and name specified during transaction definition.

These created ARM metric objects are used to store all data regarding the additional information needed to provide the "shoot-transaction" with the force and angle value during each start. These values are named metrics within ARM context, with a metric type named "numeric id". A numeric id is a metric that does not change its value while the transaction is executed, therefore it has only to be provided during start(). Other types of metrics are "counters" and "gauges". See the ARM standard for details of metric types.

The two metric objects are allocated in the constructor:

    angle = new QSimpleArmNumId("Shot Angle","deg");
    force = new QSimpleArmNumId("Shot Force","[N]");

    metrics.append(angle);
    metrics.append(force);

The name of the metrics is "Shot Angle" and "Shot Force", their unit is "degree" and "Newton". They are organised in a QArmMetricList called "metrics". This is necessary since different methods from QArmTransaction are using the metric information, first during instantiation and later during start(). The "shoot-transaction" is defined as a pointer

    QSimpleArmTran *shootTransaction;

since now the shoot-Transaction needs to know that some numeric ids will be provided during start(). You might ask why, since this does not directly influence the constructor of this class. The reason can be found in the ARM standard. The number of metrics as well as their type has to be provided at the time when the transaction is registered to the ARM application. This is done when the class is instantiated. The reason for this is simple: Performance. It is better to spend some time registering a metric at the time when the program is initialised (and when classes are instantiated normally) as if all the data is provided at the time when the transaction is started. All the data needed to identify a metric (the name, the unit, the type of data etc.) is therefore defined when the definition is instantiated

    shootTransaction = new QSimpleArmTran("shot airborne",
                                          0,
                                          &metrics);

Here you see again the QArmMetricList that was created earlier. All the data provided by the metrics (name, unit, type) is now known to the transaction and there is no need to use that information when the start() method of this transaction is called. What is missing yet are the metric values. These are provided during start():

    angle->setValue(_ang);
    force->setValue(_force);
    shootTransaction->start(&metrics);

First the values are filled and afterwards the list of metrics is provided to start(). The list is the same that was provided when the class was instantiated. But now the transaction is not interested in name or unit of the metric but in its value provided earlier. It is important that the list of metrics is the same that was used earlier since the order of metrics is important.

You will see that the data provided with each metric is copied to each transaction instance by looking at the results of this example.

Compiling

The code can be compiled using the standard Qt qmake mechanism. Just go into the directory tutorial/t3 and say:

    qmake
    make

Behaviour

The behaviour is the same as with the former example with one difference: You know more about the situation when the measurement was made. An ARM expert provided with this information will be able to see the learning curve of a user shooting the cannon and trying different values. A tendency for the user might be the result, assuring that the computers performance didn't influence this curve. On the other hand, a computer that is running on its performance limit might influence the users learning curve. Both questions can be answered by analysing the data provided by the ARM instrumentation.

Exercise

No exercises defined yet.