
Czym jest ?
To jest system do zarządzania różnym sprzętem i oprogramowaniem.
TANGO obsługuje obecnie 4 platformy: Linux, Windows NT, Solaris i HP-UX.
Tutaj opisane będzie korzystanie z Linuxa (Ubuntu 18.04)
Po co to potrzebne?
Ułatwia pracę z różnym sprzętem i oprogramowaniem.
- Nie musisz się martwić o to, jak przechowywać dane w bazie danych, to już zostało zrobione za Ciebie.
- Wystarczy opisać mechanizm odczytu czujników.
- Zredukuje cały Twój kod do jednego standardu.
Gdzie to znaleźć?
Nie mogłem uruchomić go z kodu źródłowego, do pracy użyłem gotowego obrazu TangoBox 9.3.
W instrukcji opisano, jak go zainstalować z pakietów.
Z czego się składa?
- JIVE — służy do przeglądania i edytowania bazy danych TANGO.
- POGO — generator kodu dla serwerów urządzeń TANGO.
- Astor — menedżer oprogramowania dla systemu TANGO.
Będziemy interesować się tylko pierwszymi dwoma składnikami.
Obsługiwane języki programowania
- C
- C++
- Java
- JavaScript
- Python
- Matlab
- LabVIEW
Pracowałem z nim w Pythonie i C++. Tutaj jako przykład użyję C++.
Teraz przejdźmy do opisu, jak podłączyć urządzenie do TANGO i jak z nim pracować. Jako przykład weźmiemy płytkę GPS neo-6m-0-001:

Jak widać na zdjęciu, płytkę podłączamy do PC przez UART CP2102. Po podłączeniu do PC pojawia się urządzenie /dev/ttyUSB[0-N], zwykle /dev/ttyUSB0.
POGO
Teraz uruchomimy. pogo, a następnie generujemy szkielet kodu do pracy z naszą płytką.
pogo
Już miałem stworzony kod, stwórzmy go od nowa Plik->Nowy.

Otrzymujemy następujące:

Nasze urządzenie (przez urządzenie będziemy dalej rozumieć część programową) jest puste i ma dwie komendy sterujące: State & Status.
Należy je wypełnić niezbędnymi atrybutami:
Właściwość urządzenia — wartości domyślne, które przekazujemy do urządzenia w celu jego inicjalizacji, dla płytki GPS należy przekazać nazwę płytki w systemie com="/dev/ttyUSB0" i szybkość portu com baudrate=9600
Komendy — komendy do sterowania naszym urządzeniem, można im przypisać argumenty i wartości zwracane.
- STAN — zwraca aktualny stan, z Stany
- STATUS — zwraca bieżący status, to jest ciąg dodatkowy do STAN
- GPSArray — zwraca gps ciąg w postaci DevVarCharArray
Następnie definiowane są atrybuty urządzenia, które można odczytywać/pisać do niego.
Atrybuty skalarne — proste atrybuty (char, string, long itp.)
Atrybuty spektralne — jednowymiarowe tablice
Atrybuty obrazu — dwuwymiarowe tablice
Stany — stany, w jakich znajduje się nasze urządzenie.
- OTWÓRZ — urządzenie jest otwarte.
- ZAMKNIJ — urządzenie jest zamknięte.
- BŁĄD — wystąpił błąd.
- WŁĄCZONE — odbieramy dane z urządzenia.
- WYŁ. — brak danych z urządzenia.
Przykład dodawania atrybutu gps_string:

Okres pobierania czas w ms, jak często będzie aktualizowana wartość gps_string. Jeśli czas aktualizacji nie jest ustawiony, atrybut będzie aktualizowany tylko na żądanie.
Udało się:

Teraz należy wygenerować kod Plik->Generuj

Domyślnie Makefile nie jest generowany, za pierwszym razem należy zaznaczyć, aby go stworzyć. Zrobiono to, aby wprowadzone do niego zmiany nie zostały usunięte podczas nowej generacji. Utworzywszy go raz i dostosowując do swojego projektu (wprowadzenie kluczy kompilacji, dodatkowych plików), można o nim zapomnieć.
Teraz przechodzimy bezpośrednio do programowania. pogo wygenerował nam następujące:

Będą nas interesować pliki NEO6M.cpp i NEO6M.h. Przyjrzyjmy się jako przykład konstruktorowi klasy:
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
}Co tu jest i co jest najważniejsze? W funkcji init_device() następuje przydzielenie pamięci dla naszych atrybutów: gps_string & gps_array, ale to nie jest ważne. Najważniejsze tutaj, to komentarze:
/*----- PROTECTED REGION ID(NEO6M::constructor_1) ENABLED START -----*/
.......
/*----- PROTECTED REGION END -----*/ // NEO6M::constructor_1Wszystko, co znajduje się w tym bloku komentarza, podczas następnych regeneracji kodu w pogo nie zostanie usunięte!. Wszystko, co jest poza blokami, zostanie usunięte! To są miejsca, w których możemy programować i wprowadzać nasze zmiany.
Jakie główne funkcje zawiera klasa NEO6M:
void always_executed_hook();
void read_attr_hardware(vector &attr_list);
void read_gps_string(Tango::Attribute &attr);
void read_gps_array(Tango::Attribute &attr);Kiedy będziemy chcieli odczytać wartość atrybutu gps_string, zostaną wywołane funkcje w następującej kolejności: always_executed_hook, read_attr_hardware i read_gps_string. W read_gps_string nastąpi uzupełnienie gps_string wartością.
void NEO6M::read_gps_string(Tango::Attribute &attr)
{
DEBUG_STREAM << "NEO6M::read_gps_string(Tango::Attribute &attr) wchodzi... " <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
}Kompilacja
Wchodzimy do folderu z kodem źródłowym i:
makeProgram skompiluje się w folderze ~/DeviceServers.
tango-cs@tangobox:~/DeviceServers$ ls
NEO6MJIVE
jive
W bazie danych już są jakieś urządzenia, stwórzmy więc nasze Edytuj->Utwórz serwer

Teraz spróbujemy się do niego podłączyć:

Nic nie wyjdzie, najpierw trzeba uruchomić nasz program:
sudo ./NEO6M neo6m -v2Do podłączenia się do portu com mogę potrzebować tylko uprawnień root-a. v — poziom logowania.
Teraz możemy się połączyć:

Klient
Patrzenie na wykresy jest oczywiście dobre, ale potrzebujemy czegoś bardziej użytecznego. Napiszemy klienta, który połączy się z naszym urządzeniem i pobierze z niego dane.
#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);
}
}Jak kompilować:
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++Wynik:
tango-cs@tangobox:~/workspace/c$ ./a.out
$GPRMC,,V,,,,,,,,,,N*53
$GPRMC,,V,,,,,,,,,,N*53
$GPRMC,,V,,,,,,,,,,N*53Otrzymaliśmy wynik w postaci zwrotu polecenia, pobierania atrybutów i tablicy znaków.
Linki
Artykuł pisałem dla siebie, ponieważ po pewnym czasie zaczynam zapominać, jak i co robić.
Dziękujemy za uwagę.
Źródło: habr.com
