O servidor consiste em uma máquina conectada à rede local com suporte para a ferramenta NetCat[1].

Para comunicação com o servidor foi escolhida essa ferramenta por sua natureza nativa no Raspian e praticidade e abrangência de uso. Tem inúmeras utilidades no escopo de comunicação TCP IP.

  • Recebimento de informações no servidor

Para o servidor foi escrito um script para Bash que inicializa a ferramenta NetCat dentro de uma pasta específica para armazenamento dos dados das câmeras. Assim, o servidor abre uma porta na rede e fica recebendo continuamente os arquivos do Raspberry Pi por ela.

Os dados da câmera Pixy são recebidos e armazenados em formato de texto e esta atualização se dá continuamente dentro de intervalos fixos de tempo, determinados no script. Assim, disponibilizando arquivos de texto de tempos em tempos para que o software de análise de dados trabalhe.

  • Testes com a Pixy

Para serem efetivados testes do processamento, foi necessário gerar os arquivos de texto enviados pela Pixy com a esteira funcionando. E além disso, também foram necessários testes para definir os limites da esteira nas coordenadas x e y informadas pela Pixy.

Para este último caso, foi colocado um objeto em cada limite da esteira, e obtidas as informações de 10 frames como na figura abaixo:

thumbnail_MarcaçoesDeXeY

Dessa forma, foi possível observar pelos valores de y que a esteira 1 fica entre os valores 12 e 66, e a esteira 2 fica entre os valores 106 e 159 das coordenadas y. Os objetos testes foram colocados apenas no início de cada esteira, então os valores x correspondem aproximadamente à coordenada x do início das esteiras.

Com a esteira funcionando, foram gerados 12 arquivos de texto, como o mostrado na figura abaixo, que foram utilizados para simular o teste no software. A partir desses testes também foi possível identificar os valores de x correspondente ao final das esteiras, já que os objetos passaram pela esteira toda.

Captura de Tela 2017-05-17 às 11.09.13

  • Processamento dos dados

No mesmo intervalo de tempo especificado anteriormente, em que são recebidos novos arquivos de texto com as informações geradas pela Pixy, o programa principal lê esse arquivo de texto, e processa cada frame.

public static void main(String[] argv) {

int menoresX[]; //armazena os últimos valores das coordenadas x dos últimos produtos a entrar em cada uma das esteiras que foram obtidos ao final da última Thread
 Timer timer; //timer responsável por invocar o processamento do arquivo de texto recebido de tempos em tempos
 TimerTask task; //tarefa responsável por analisar o arquivo de texto e encapsular os dados
 TimerTask task_OEEupdate; //tarefa responsável por atualizar o indicador OEE ao longo do dia
 TimerTask task_cancel; //tarefa responsável por parar o timer ao fim do expediente do dia

}

Um frame é uma foto tirada pela Pixy, que contém informações sobre cada objeto contido na foto naquele momento, como o código referente a cor, as coordenadas x e y, largura e altura, e data e hora em que foi obtida essa foto. Essas informações são encapsuladas dentro de objetos dentro da TimerTask definida na main, e após finalizada a leitura do arquivo, é lançada uma Thread para que sejam processados os dados destes frames.

public class Product implements Comparable  {
 //classe que armazena os dados de cada objeto identificado pela Pixy

private String sig; //cor do objeto (signature)
 private int x,y; //coordenadas x e y do objeto
 private int width,height; //largura e altura do objeto
 private DateProcess date; //classe definida manualmente que armazena a data e a hora em que o produto foi identificado
 private Integer ID; //identificação, utilizada em conexão com o banco de dados

public int compareTo(Product o); //utilizada para ordenar os produtos de cada frame em ordem crescente pela coordenada x

}

public class Frame {
 //classe que armazena a lista de objetos em um frame

private int frameID; //ID do frame informado pela pixy
 private List products; // lista dos objetos no frame

}

TimerTask task {
 //tarefa invocada de tempos em tempos na main responsável por encapsular os objetos e chamar a Thread que realiza o processamento dos dados dos frames

BufferedReader br; //objeto utilizado para leitura do arquivo de texto
 ArrayList frames; //lista dos frames encapsulados
 ProcessThread t; //Thread que vai analisar os objetos encapsulados na lista de frames para determinar se entrou um novo objeto

}

Basicamente, são comparadas as posições dos objetos em cada frame, e o algoritmo verifica se foi detectado um novo objeto em cada uma das esteiras através das posições subsequentes em frames consecutivos, e se o objeto está dentro do padrão esperado (para isso, foi considerada a área do objeto).

Caso seja detectado um novo objeto, é inserida uma nova tupla na tabela correspondente no banco de dados, informando a cor do objeto, se está dentro do padrão, e a data e hora em que o mesmo passou pelo centro da esteira.

public class ProcessThread extends Thread {

static final int X1,X2; //coordenadas que determinam o início e fim das esteiras
 static final int Y1_ESTEIRA1, Y2_ESTEIRA1, Y1_ESTEIRA2, Y2_ESTEIRA2; //coordenadas que delimitam a localização de cada uma das esteiras
 static final int MENOR_AREA,MAIOR_AREA; //valores que determinam as menores e maiores áreas aceitáveis dos objetos

private Frame[] frames; //frames encapsulados na task
 private int[] menoresX; //últimos valores das coordenadas x dos últimos produtos a entrar em cada uma das esteiras
 private ArrayList novosProdutos;
 private ArrayList padrao;               //listas que armazenam informações dos novos produtos que entraram na esteira, utilizados no software dos alertas

public void run(); //método herdado da classe Thread, em que, nesse caso, é realizado o processamento dos dados do frame, e invocado o software dos alertas
 public void novoObjeto(Product p, boolean estaDentrodoPadrao); //função invocada qdo é identificado um novo objeto, e o mesmo é adicionado às listas neste escopo, e adicionado ao banco de dados

}

Após a análise de todos os frames lidos no arquivo .txt recebido, as informações dos novos objetos inseridos no banco de dados estão disponíveis para análise do software gerador de alertas.

A TimerTask “task_OEEupdate” é responsável por fazer a atualização de minuto em minuto dos valores do indicador OEE. A cada chamada dessa tarefa, a variável tempoProducao é incrementada, indicando o tempo em minutos em que o sistema está funcionando.

Na variável “ultimaConsulta” é guardado o ID do último produto já computado para esse índice. Dessa forma, a cada execução, são considerados para os cálculos do OEE apenas o produto do próximo ID até o último inserido na tabela de produtos.

Somam-se então, esses novos produtos detectados à variável “qtdeProduzida”, e a quantidade desses produtos que estão dentro do padrão é somada à variável “qtdePadrão”. São feitas as divisões necessárias para o indicador, o resultado é atualizado na tabela OEE do banco de dados, e o gráfico é renovado dessa forma ao longo do dia, indicando se a produção está correspondendo às expectativas.

static int tempoProducaoTeorico = 600;
static int qtdeProduzidaTeorica = 27000;
static int qtdeProduzida = 0;
static int tempoProducao = 0;
static int qtdePadrao = 0;
static int ultimaConsulta = 0;

task_OEEupdate = new TimerTask();
  • Análise dos dados para gerar alertas

Após obter a lista de objetos que entraram na esteira, é preciso uma análise de padrões para gerar os alertas de irregularidades na produção.

Primeiramente, o usuário que deseja analisar a produção adiciona na página web (Ver a seção Página Web para mais informações) quais os padrões desejados, como cor, tamanho e quantidade produzida por hora. Esses padrões estão armazenados em um banco de dados online que o servidor possui acesso. Assim os alertas básicos são gerados comparando os padrões desejados com os padrões encontrados nos produtos analisados, armazenados no banco de dados e posteriormente exibidos na Página Web.

public class Alert {

    private String text;
    private DateProcess date;
    private Integer priority;
    private String mesage;
    private Integer ID;

    //Classe chamada para a análise dos produtos adicionados
    public static void generateAlert(ArrayList novosProdutos, ArrayList padrao) throws SQLException, ClassNotFoundException {
        pattern = p.createPattern(1); //busca no banco de dados o padrão a ser comparado
        
        //Para cada produto no array, compara cor, tamanho e intervalo
        //Prioridades dos alertas: 0-intervalo de tempo,1-tamanho,2-cor
        for (int i = 0; i < novosProdutos.size(); i++) {             //compara cor do objeto com o padrão             if (cor diferente da padrão) {                 alert.incluir(a); //insere no banco de dados o alerta             }             //utiliza array de padrão calculado anteriormente para criar alerta se fora do padrão de tamanho             if (fora do padrão de tamanho) {                 alert.incluir(a); //insere no banco de dados o alerta             }             //compara o intervalo entre o anterior e o próximo com o padrão e veja se está fora de um intervalo             if (i > 0) {
                if (intervalo entre os produtos estão no intervalo padrão) {
                    alert.incluir(a); //insere no banco de dados o alerta
                }
            }else{
                if (intervalo do produto está entre o intervalo padrão) {
                    alert.incluir(a); //insere no banco de dados o alerta
                }
            }          

        }
        alert.closeConection();//fecha a conexão com o banco de dados
    }
}

Para a análise inteligente é, no começo da execução, estabelecido um padrão de intervalo de tempo entre dois produtos baseado na média de intervalos de pelo menos 10 produtos. Com esse padrão estabelecido é comparado o intervalo em produtos novamente, se não estiver nesse padrão com uma margem de tempo previamente estabelecida um alerta é gerado. Se pelo menos 5 alertas forem gerados em sequência é admitido que a velocidade da esteira ou a quantidade de produtos foi alterada e um novo padrão é buscado.

[1] https://www.vivaolinux.com.br/artigo/Netcat-O-canivete-suico-do-TCP-IP