main

Что такое TANGO?


Это система для управления различным оборудованием и программным обеспечением.
TANGO поддерживает 4 платформы на данный момент: Linux, Windows NT, Solaris и HP-UX.
Здесь будет описана работа с Linux(Ubuntu 18.04)


Для чего нужно?


Упрощает работу с различным оборудованием и софтом.


  • Вам не нужно думать о том как хранить данные в БД, это уже сделано за Вас.
  • Нужно только описать механизм опроса датчиков.
  • Сводит весь Ваш код к одному стандарту.

Где взять?



Из исходников не смог ее запустить, для работы использовал готовый образ TangoBox 9.3.
В инструкции описано как ставить из пакетов.


Из чего она состоит?


  • JIVE — служит для просмотра и редактирования базы данных TANGO.
  • POGO — генератор кода для серверов устройств TANGO.
  • Astor — программный менеджер для системы TANGO.

Нас будут интересовать только первые два компонента.


Поддерживаемые языки программирования


  • C
  • C++
  • Java
  • JavaScript
  • Python
  • Matlab
  • LabVIEW

Я работал с ней на python & c++. Здесь в качестве примера будет использоваться c++.


Теперь перейдем к описанию как подключить устройство к TANGO и как с ним работать. В качестве примера будет взята плата GPS neo-6m-0-001:


image


Как видно на картинке плату к ПК подключаем через UART CP2102. При подключении к ПК появляется устройство /dev/ttyUSB[0-N], обычно /dev/ttyUSB0.


POGO


Теперь запустим pogo, и с генерируем скелет код для работы с нашей платой.


pogo

image


У меня уже был создан код, создадим его заново File->New.


image


Получаем следующее:


image


Наше устройство(под устройством в дальнейшем будет иметься ввиду программная часть) пустое и имеет две команды управления: State & Status.


Его нужно заполнить необходимыми атрибутами:


Device Property — значения по умолчанию которые передаем в устройство для его инициализации, для платы GPS нужно передать имя платы в системе com="/dev/ttyUSB0" и скорость com порта baudrade=9600


Commands — команды управления нашим устройством, им можно задать аргументы и возвращаемое значение.


  • STATE — возвращает текущее состояние, из States
  • STATUS — возвращает текущий статус, это строковое дополнение к STATE
  • GPSArray — возвращает gps строку в виде DevVarCharArray

Далее задаются атрибуты устройства которые можно читать/писать в/из него.
Scalar Attributes — простые атрибуты (char, string, long и т.п.)
Spectrum Attributes — одномерные массивы
Image Attributes — двумерные массивы


States — состояния в котором находится наше устройство.


  • OPEN — устройство открыто.
  • CLOSE — устройство закрыто.
  • FAILT — ошибка.
  • ON — принимаем данные с устройства.
  • OFF — нет данных с устройства.

Пример добавления атрибута gps_string:


image


Polling period время в мс, как часто будет обновляться значение gps_string. Если время обновления не задать, то атрибут будет обновляться только по запросу.


Получилось:


image


Теперь нужно с генерировать код File->Generate


image


По умолчанию Makefile не генерируется, в 1-ый раз нужно поставить галочку что бы его создать. Это сделано для того что бы внесенные в него правки не удалялись при новой генерации. Создав его единожды и настроив под свой проект(прописать ключи компиляции, доп. файлы) можно забыть про него.


Теперь переходим непосредственно к программированию. pogo с генерировал нам следующее:


image


Нас будут интересовать NEO6M.cpp & NEO6M.h. Рассмотрим для примера конструктор класса:


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
}

Что здесь есть и что здесь главное? В функции init_device() происходит выделение памяти для наших атрибутов: gps_string & gps_array, но это не важно. Самое важное здесь, это комментарии:


/*----- PROTECTED REGION ID(NEO6M::constructor_1) ENABLED START -----*/
    .......
/*----- PROTECTED REGION END -----*/    //  NEO6M::constructor_1

Все что находится внутри этого блока комментария при последующих перегенерациях кода в pogo не будет удаляться!. Все что в не блоках будет! Это те места где мы можем программировать и вносить свои правки.


Теперь какие главные функции содержит класс NEO6M:


void always_executed_hook();
void read_attr_hardware(vector<long> &attr_list);
void read_gps_string(Tango::Attribute &attr);
void read_gps_array(Tango::Attribute &attr);

Когда мы захотим прочитать значение атрибута gps_string, будут вызваны функции в следующем порядке: always_executed_hook, read_attr_hardware и read_gps_string. В read_gps_string произойдет заполнение gps_string значением.


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
}

Компиляция


Заходим в папку с исходниками и:


make

Программа скомпилируется в папку ~/DeviceServers.


tango-cs@tangobox:~/DeviceServers$ ls
NEO6M

JIVE


jive

image


В БД уже есть какие-то устройства, создадим теперь наше Edit->Create Server


image


Теперь попробуем подключиться к нему:


image


Ни чего не выйдет, сначала надо запустить нашу программу:


sudo ./NEO6M neo6m -v2

Подключиться к com порту у меня можно только с правами root-а. v — уровень логирования.


Теперь можем подключиться:


image


Клиент


В графике смотреть на картинки конечно хорошо, но нужно что-то более полезное. Напишем клиент который будет подключаться к нашему устройству и забирать с него показания.


#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);
    }
}

Как компилировать:


g++ gps.cpp -I/usr/local/include/tango -I/usr/local/include -I/usr/local/include -std=c++0x -Dlinux -L/usr/local/lib -ltango -lomniDynamic4 -lCOS4 -lomniORB4 -lomnithread -llog4tango -lzmq -ldl -lpthread -lstdc++

Результат:


tango-cs@tangobox:~/workspace/c$ ./a.out 
$GPRMC,,V,,,,,,,,,,N*53

$GPRMC,,V,,,,,,,,,,N*53

$GPRMC,,V,,,,,,,,,,N*53

Получили результат в качестве возврата команды, взятия атрибутов строки и массива символов.


Ссылки



Статью писал для себя, потому что спустя некоторое время начинаю забывать как и что делать.


Спасибо за внимание.