
O que é ?
Este é um sistema para gerenciar diversos equipamentos e softwares.
Atualmente, o TANGO suporta 4 plataformas: Linux, Windows NT, Solaris e HP-UX.
Aqui descreveremos como trabalhar com Linux (Ubuntu 18.04)
Para que serve?
Facilita o trabalho com diversos equipamentos e softwares.
- Você não precisa se preocupar em como armazenar dados no banco de dados, isso já foi feito por você.
- Você só precisa descrever o mecanismo de consulta dos sensores.
- Reúne todo o seu código em um único padrão.
Onde encontrar?
Não consegui iniciá-lo a partir dos fontes, utilizei a imagem pré-pronta TangoBox 9.3.
A instrução descreve como instalar a partir de pacotes.
Do que é composto?
- JIVE — serve para visualizar e editar o banco de dados TANGO.
- POGO — gerador de código para servidores de dispositivos TANGO.
- Astor — gerenciador de software para o sistema TANGO.
Estaremos interessados apenas nos dois primeiros componentes.
Linguagens de programação suportadas
- C
- C++
- Java
- JavaScript
- Python
- Matlab
- LabVIEW
Trabalhei com ela em python & c++. Aqui, como exemplo, usaremos c++.
Agora vamos descrever como conectar um dispositivo ao TANGO e como trabalhá-lo. Para exemplo, utilizaremos o módulo GPS neo-6m-0-001:

Como pode ser visto na imagem, conectamos o módulo ao PC através do UART CP2102. Ao conectar ao PC, aparece o dispositivo /dev/ttyUSB[0-N], normalmente /dev/ttyUSB0.
POGO
Agora vamos executar pogo, e gerar o código esqueleto para trabalhar com nosso módulo.
pogo
Eu já tinha um código criado, vamos recriá-lo Arquivo->Novo.

Obtivemos o seguinte:

Nosso dispositivo (daqui em diante, referindo-se à parte de software) está vazio e possui dois comandos de controle: Estado & Status.
Ele precisa ser preenchido com os atributos necessários:
Propriedade do Dispositivo — valores padrão que passamos para o dispositivo para sua inicialização, para o módulo GPS precisamos passar o nome do módulo no sistema com="/dev/ttyUSB0" e a velocidade da porta serial baudrate=9600
Comandos — comandos de controle de nosso dispositivo, podemos atribuir argumentos e um valor de retorno.
- ESTADO — retorna o estado atual, de Estados
- STATUS — retorna o status atual, que é um complemento em string a ESTADO
- GPSArray — retorna gps uma string no formato DevVarCharArray
A seguir, são definidos os atributos do dispositivo que podem ser lidos/escritos nele.
Atributos Escalares — atributos simples (char, string, long, etc.)
Atributos de Espectro — arrays unidimensionais
Atributos de Imagem — arrays bidimensionais
Estados — estados em que nosso dispositivo se encontra.
- ABERTO — dispositivo aberto.
- FECHADO — dispositivo fechado.
- FALHA — erro.
- ATIVADO — recebendo dados do dispositivo.
- OFF — sem dados do dispositivo.
Exemplo de adição de atributo gps_string:

Período de sondagem tempo em ms, com que frequência o valor gps_string será atualizado. Se o tempo de atualização não for definido, o atributo será atualizado apenas sob demanda.
Conseguido:

Agora precisamos gerar o código Arquivo->Gerar

Por padrão, o Makefile não é gerado, na primeira vez é necessário marcar a caixa para criá-lo. Isso é feito para que as modificações nele feitas não sejam perdidas na nova geração. Criando-o uma vez e configurando-o para o seu projeto (especificar as chaves de compilação, arquivos adicionais), você pode esquecê-lo.
Agora vamos para a programação. O pogo nos gerou o seguinte:

Vamos nos interessar por NEO6M.cpp & NEO6M.h. Vamos considerar, por exemplo, o construtor da classe:
NEO6M::NEO6M(Tango::DeviceClass *cl, string &s)
: TANGO_BASE_CLASS(cl, s.c_str())
{
/*----- REGIÃO PROTEGIDA ID(NEO6M::constructor_1) HABILITADA INÍCIO -----*/
init_device();
/*----- REGIÃO PROTEGIDA FIM -----*/ // NEO6M::constructor_1
}O que temos aqui e qual é o principal? Na função init_device() ocorre a alocação de memória para nossos atributos: gps_string & gps_array, mas isso não importa. O mais importante aqui, são os comentários:
/*----- PROTECTED REGION ID(NEO6M::constructor_1) ENABLED START -----*/
.......
/*----- PROTECTED REGION END -----*/ // NEO6M::constructor_1Tudo o que está dentro deste bloco de comentários nas próximas regenerações de código no pogo não será deletado!. Tudo o que não estiver em blocos será! Esses são os locais onde podemos programar e fazer nossas alterações.
Agora, quais são as funções principais que a classe contém 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);Quando quisermos ler o valor do atributo gps_string, as funções serão chamadas na seguinte ordem: always_executed_hook, read_attr_hardware e read_gps_string. Em read_gps_string, o gps_string será preenchido com o valor.
void NEO6M::read_gps_string(Tango::Attribute &attr)
{
DEBUG_STREAM << "NEO6M::read_gps_string(Tango::Attribute &attr) entrando... " <attr_gps_string_read = Tango::string_dup(this->gps.c_str());
attr.set_value(attr_gps_string_read);
/*----- REGIÃO PROTEGIDA FIM -----*/ // NEO6M::read_gps_string
}Compilação
Vamos à pasta com os códigos fonte e:
makeO programa será compilado na pasta ~/DeviceServers.
tango-cs@tangobox:~/DeviceServers$ ls
NEO6MJIVE
jive
Já existem alguns dispositivos no banco de dados, agora vamos criar o nosso Editar->Criar Servidor

Agora vamos tentar nos conectar a ele:

Nada vai funcionar, primeiro precisamos iniciar o nosso programa:
sudo ./NEO6M neo6m -v2Conectar à porta com só pode ser feito com permissões root-a. v — nível de registro.
Agora podemos nos conectar:

Cliente
Ver imagens no gráfico é bom, mas precisamos de algo mais útil. Vamos escrever um cliente que se conectará ao nosso dispositivo e coletará as leituras dele.
#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);
}
}Como compilar:
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++Resultado:
tango-cs@tangobox:~/workspace/c$ ./a.out
$GPRMC,,V,,,,,,,,,,N*53
$GPRMC,,V,,,,,,,,,,N*53
$GPRMC,,V,,,,,,,,,,N*53Recebemos o resultado como retorno do comando, obtendo os atributos da string e do array de caracteres.
Links
Escrevi este artigo para mim, porque depois de um tempo começo a esquecer como e o que fazer.
Obrigado pela atenção.
Fonte: habr.com
