It is a system for managing various hardware and software.
TANGO currently supports 4 platforms: Linux, Windows NT, Solaris and HP-UX.
Working with Linux (Ubuntu 18.04) will be described here
What is it for?
Simplifies work with various hardware and software.
You do not need to think about how to store data in the database, it is already done for you.
It is only necessary to describe the mechanism for polling sensors.
From the sources I could not run it, I used the ready-made TangoBox 9.3 image for work.
The instructions describe how to install from packages.
What does it consist of?
JIVE - serves to view and edit the TANGO database.
POGO β code generator for TANGO device servers.
Astor β program manager for the TANGO system.
We will only be interested in the first two components.
Supported programming languages
C
C++
Java
JavaScript
Python
Matlab
LabVIEW
I worked with her in python & c++. Here c++ will be used as an example.
Now let's move on to the description of how to connect the device to TANGO and how to work with it. The fee will be taken as an example. GPS neo-6m-0-001:
As you can see in the picture, we connect the board to the PC via UART CP2102. Device appears when connected to PC /dev/ttyUSB[0-N], usually /dev/ttyUSB0.
POGO
Now let's run pogo, and with generate the skeleton code to work with our board.
pogo
I have already created the code, let's create it again File->New.
We get the following:
Our device (under the device in the future we will mean the software part) is empty and has two control commands: State & Status.
It must be filled with the necessary attributes:
Device Property - default values ββββthat we pass to the device to initialize it, for the GPS board, you need to transfer the name of the board in the system com="/dev/ttyUSB0" and com port speed baugrade=9600
Commands - commands to control our device, they can be given arguments and a return value.
STATE - returns the current state, from States
STATUS - returns the current status, this is a string complement to STATE
GPSArray returns gps line in the form DevVarCharArray
Next, the attributes of the device that can be read / written to / from it are set. Scalar Attributes - simple attributes (char, string, long, etc.) Spectrum Attributes - one-dimensional arrays Image Attributes - two-dimensional arrays
States - the state in which our device is located.
OPEN β the device is open.
CLOSE β the device is closed.
FAILT - error.
ON β receive data from the device.
OFF β no data from the device.
An example of adding an attribute gps_string:
polling period time in ms, how often the value of gps_string will be updated. If the update time is not set, then the attribute will be updated only on request.
Happened:
Now you need to generate code File->Generate
By default, the Makefile is not generated, the first time you need to check the box to create it. This is done so that the changes made to it are not deleted during the new generation. Having created it once and configured it for your project (prescribe compilation keys, additional files), you can forget about it.
Now let's move on to programming. pogo generated the following for us:
We will be interested in NEO6M.cpp & NEO6M.h. Let's take a class constructor as an example:
NEO6M::NEO6M(Tango::DeviceClass *cl, string &s)
: TANGO_BASE_CLASS(cl, s.c_str())
{
/*----- PROTECTED REGION ID(NEO6M::constructor_1) ENABLED START -----*/
init_device();
/*----- PROTECTED REGION END -----*/ // NEO6M::constructor_1
}
What is there and what is the main thing here? In the init_device() function, memory is allocated for our attributes: gps_string & gps_array, but it is not important. The most important thing here, these are the comments:
/*----- PROTECTED REGION ID(NEO6M::constructor_1) ENABLED START -----*/
.......
/*----- PROTECTED REGION END -----*/ // NEO6M::constructor_1
Everything that is inside this comment block will not be included in subsequent code regenerations in pogo move away!. Everything that is not in blocks will be! These are the places where we can program and make our edits.
Now what are the main functions of the class NEO6M:
When we want to read the value of an attribute gps_string, the functions will be called in the following order: always_executed_hook, read_attr_hardware ΠΈ read_gps_string. The read_gps_string will be populated with the gps_string value.
void NEO6M::read_gps_string(Tango::Attribute &attr)
{
DEBUG_STREAM << "NEO6M::read_gps_string(Tango::Attribute &attr) entering... " << endl;
/*----- PROTECTED REGION ID(NEO6M::read_gps_string) ENABLED START -----*/
// Set the attribute value
*this->attr_gps_string_read = Tango::string_dup(this->gps.c_str());
attr.set_value(attr_gps_string_read);
/*----- PROTECTED REGION END -----*/ // NEO6M::read_gps_string
}
Compilation
Go to the source folder and:
make
The program will be compiled into the ~/DeviceServers folder.
tango-cs@tangobox:~/DeviceServers$ ls
NEO6M
JIVE
jive
There are already some devices in the database, now let's create our Edit->Create Server
Now let's try to connect to it:
Nothing will come of it, first you need to run our program:
sudo ./NEO6M neo6m -v2
I can connect to the com port only with rights root-but. v - logging level.
Now we can connect:
Customer
In graphics, looking at pictures is certainly good, but something more useful is needed. Let's write a client that will connect to our device and take readings from it.
#include <tango.h>
using namespace Tango;
int main(int argc, char **argv) {
try {
//
// create a connection to a TANGO device
//
DeviceProxy *device = new DeviceProxy("NEO6M/neo6m/1");
//
// Ping the device
//
device->ping();
//
// Execute a command on the device and extract the reply as a string
//
vector<Tango::DevUChar> gps_array;
DeviceData cmd_reply;
cmd_reply = device->command_inout("GPSArray");
cmd_reply >> gps_array;
for (int i = 0; i < gps_array.size(); i++) {
printf("%c", gps_array[i]);
}
puts("");
//
// Read a device attribute (string data type)
//
string spr;
DeviceAttribute att_reply;
att_reply = device->read_attribute("gps_string");
att_reply >> spr;
cout << spr << endl;
vector<Tango::DevUChar> spr2;
DeviceAttribute att_reply2;
att_reply2 = device->read_attribute("gps_array");
att_reply2.extract_read(spr2);
for (int i = 0; i < spr2.size(); i++) {
printf("%c", spr2[i]);
}
puts("");
} catch (DevFailed &e) {
Except::print_exception(e);
exit(-1);
}
}