Petfeeder, alimentador automático para pets
Os compromissos diários que mantém nossa sociedade cada vez mais ocupada, com tempo livre escasso, podem se tornar um impecilio para a tomada de decisão quanto a adoção ou aquisição de um pet, já que este consumidor irá confrontar sua agenda de compromissos com sua disponibilidade de lhe oferecer atenção e cuidado. Logo, uma sociedade que cada vez mais encontra conforto e carinho em pets (cachorros, gatos, aves, repteis e etc), tem um desafio diário em prezar pela correta alimentação desses queridos amigos.
quarta, 27 de novembro de 2019
petfeederalimentador automáticopet

Em resposta a este problema surge a oportunidade de fornecer um equipamento que seja capaz de controlar e avaliar a alimentação dos animais domésticos, o qual é o objetivo deste trabalho

Introdução


O ser humano sempre viveu rodeado de animais, adaptando-se a estes e vice-versa, consoante as suas necessidades. Atualmente e mais do que nunca, os animais de companhia têm exercido uma função de extrema importância na sociedade, ajudando a preencher lacunas que a própria sociedade criou.

Pets em geral são como que uma terapia para problemas de solidão, por exemplo: as pessoas idosas buscam alguém de quem possam cuidar e trocar afeto, já as pessoas residentes em casas agregam a presença de um animal à segurança e se sentem mais seguras com um cão por perto, buscando a companhia de animais de médio e grande porte. Pelo fato de ficarem mais tempo em suas residências, um animal de estimação ajuda a preencher o tempo, fazendo companhia, além de dar e receber atenção.

Contudo há um problema em garantir uma alimentação adequada aos pets, ocasionado pela indisponibilidade de tempo de seus criadores, gerando desde doenças por falta de nutrientes até mesmo o óbito do animal. Por esses e outros motivos surgiu-se a ideia de desenvolver de um dispositivo automático que auxilie os donos de pets a garantir a alimentação adequada para seus animais, através de um alimentador automatizado onde o processo de alimentar o pet é feito em períodos de tempo e quantidade de alimento estabelecidos pelo criador. Podendo ainda unir a estes quesitos a geração de relatórios de frequência e quantidade de alimento ingerida.

Análise de propostas no mesmo seguimento


Buscou-se no mercado por equipamentos que atendessem às seguintes premissas:

  • Dispensar comida em horários programados, de forma automática
  • Fácil manipulação, manutenção e higienização
  • Com pesagem de alimento
  • Transmissão de vídeo ao vivo
  • Conexão remota para programação e/ou dispensa de comida

Não houve um equipamento que atendesse a todos os requisitos supracitados, mas houveram alguns que chamaram a atenção, como:

Kit Comedouro

Kit Comedouro

Neste caso, o equipamento não possui nenhum tipo de controle de dispensa de alimento, não possui nenhuma inteligência, porém se mostra ser de fácil instalação, uso, manutenção e higienização.

Alimentador 18l

Alimentador 18l

Este dispositivo nada mais seria que um tambor de comida com um timer (de mercado) acoplado, o qual permite a programação da alimentação, sendo de fácil instalação e uso.

Alimentador Digital

Alimentador Digital

Alimentador digital automático sofisticado com todos os itens necessários citados, excluindo a pesagem do alimento.

Esta pesquisa possibilitou o melhor entendimento do mercado e levou a equipe a discussão de qual seria a melhor forma de entregar esta experiência ao usuário. Por unanimidade, a equipe optou por criar um design mecânico que fosse imprimível em qualquer impressora 3D e utilizasse material de fácil aquisição no mercado para acabamento do dispositivo, tudo isso seria entregue de forma digital para entusiastas que quisessem construir o dispositivo em casa/ou peças impressas para aqueles com nem tanta curiosidade, ficando apenas como parte comercializável (de fato) a eletrônica e o acesso ao aplicativo/portal.

Métodos e Ferramentas


A seguir a descrição do processo de criação do PetFeeder, alimentador automático para pets.

Design Mecânico

Para a criação do alimentador, foi projetado com um design mecânico que pudesse ser construído a partir de qualquer impressora 3D, que possa ser capaz de realizar a impressão de todas as suas peças de fixação e que também o resto de seus componentes fossem encontrados facilmente no mercado.

O alimentador é constituído por 2 (dois) canos, 5 (cinco) elementos de fixação de PVC, e 4 (quatro) peças de fixação impressas em impressora 3D.

Conta com balança acoplada ao dispenser de ração para rastrear a quantidade de comida depositada. O protótipo possui um sensor de distância capaz de identificar se o nível de alimento está alto ou baixo, possui um relógio para executar eventos agendados, conexão wireless e display LCD para interação com usuário.

A forma básica da operação é através de um portal-web, onde é possível configurar os horários para despejo de comida e também sua quantidade.

Localmente também é possível colocar comida através dos botões de acesso do dispositivo.

Suporte parede

Suporte Parede

Rosca sem fim

Rosca sem fim

Balança

Balança

Componentes Eletrônicos

Os componentes eletrônicos a seguir constituem o PetFeeder:

Componentes eletrônicos

Componentes eletrônicos

  • Arduino Uno: responsável por controlar todos os outros componentes e também pela comunicação com o servidor.
  • Display de cristal líquido: pode exibir texto no formato 16 colunas x 2 linhas. Nele serão exibidas mensagens inerentes do processo do alimentador.
  • Motor passo: realiza o giro da rosca sem fim para ejetar comida.
  • Modulo Wifi ESP01: responsável pela conexão wireless com o Arduino, controlados por comandos AT.
  • Conversor analógico digital de 24 bits: transforma a tensão gerada pela célula de carga em dados digitais.
  • Relógio tempo real: para contagem de tempo, possui bateria externa para não perder dados ao ser desligado.
  • Sensor Carga: ao sofrer uma deformação ocasionada por um peso externo a célula de carga gera uma tensão proporcional ao peso, permitindo assim o arduino saber o quanto de comida tem no pote, por exemplo.
  • Sensor Distância: por ultrassom é capaz de medir distância entre dois pontos, proporcionando ao Arduino saber o quanto de comida tem no reservatório.
  • Botões: utilizados para interação local com o alimentador.

Topologia

O alimentador se reporta a um servidor dedicado, o qual arquiva informações relevantes e também pede ao alimentador que execute alguns comandos, como por exemplo: colocar comida, alterar horário alimentação, etc. Por fim, os usuários podem interagir com o alimentador remotamente através de um site ou localmente através dos botões do alimentador.

Topologia alimentador

Topologia alimentador

Protocolo Comunicação

A comunicação entre alimentador e servidor é via sockets UDP (User Datagram Protocol) podendo ser criptografada ou não. Tanto o programa que roda no servidor e o programa que roda no Arduino foram feitos em C++. A comunicação se faz da seguinte maneira:

Protocolo comunicação

Protocolo comunicação

Comunicação Alimentador - Servidor

A cada 5 minutos o alimentador envia um PACKET REPORT ao servidor, o qual contém a estrutura pré-definida:

typedef struct{
    // Os pacotes sempre se iniciam com STX
    unsigned char iniciador; 
    // 0: plaintext 1: criptografado
    unsigned char modo;
}TPacketInit;

typedef struct{
    // Assinatura do pacote, conhecido pelo 
    // cliente e servidor
    char sign[10];
    // Tipo do pacote sendo enviado
    unsigned char id;
    // Sequencia do pacote
    unsigned long seq;
    // Status do alimentador 0: OK, 1: em erro
    unsigned char st; 
    // Numero de serie do alimentador
    char sn[10];
}TPacketID;

typedef struct{
    TPacketInit init;
    TPacketID pid;
    // Tempo que alimentador esta ligado
    unsigned long uptime; 
    // Nivel de alimento disponivel
    unsigned short nivel_alm; 
    // Peso do pote de comida
    unsigned short peso; 
    // Horarios de alimentação, no maximo 4
    char horario_alm[24];
    // Quantidade de alimento a ser colocado 
    // no evento
    unsigned short qtde_alm;
    // Bytes de validação do pacote
    unsigned short crc; 
}TPacketReport;

Estes dados são gravados no banco de dados, na tabela incoming, sendo que para toda inserção é gerado um timestamp no campo datahora.

CREATE TABLE `incoming` (
    `id` INT(10) UNSIGNED NOT NULL 
        AUTO_INCREMENT,
	`token` INT(10) UNSIGNED NOT NULL,
	`datahora` DATETIME NOT NULL,
	`pid` INT(11) NOT NULL,
	`seq` INT(10) UNSIGNED NOT NULL,
	`st` INT(11) NOT NULL,
	`uptime` INT(10) UNSIGNED NOT NULL,
	`sn` VARCHAR(10) NOT NULL,
	`nivel_alm` INT(11) NOT NULL,
	`peso` INT(11) NOT NULL,
	`horario_alm` VARCHAR(23) NOT NULL,
	`qtde_alm` INT(11) NOT NULL,
	PRIMARY KEY (`id`)
);

Logo o servidor pesquisa na tabela outgoing, se há algum comando para ser retornado ao alimentador.

CREATE TABLE `outgoing` (
    `id` INT(10) UNSIGNED NOT NULL 
        AUTO_INCREMENT,
	`sn_device` VARCHAR(10) NOT NULL,
	`datahora_insert` DATETIME NOT NULL,
	`cmd` INT(11) NOT NULL,
	`valor` VARCHAR(30) NOT NULL,
    `datahora_realizado` DATETIME NULL 
        DEFAULT NULL,
	`realizado` INT(11) NULL DEFAULT NULL,
	PRIMARY KEY (`id`),
	INDEX `FK_SN_DEVICE` (`sn_device`),
    CONSTRAINT `FK_SN_DEVICE`
        FOREIGN KEY (`sn_device`)
        REFERENCES `device` (`sn`)
);

O servidor então retorna uma mensagem ao alimentador do tipo PACKET RESPONSE:

typedef struct{
	TPacketInit init;
    TPacketID pid;
    // Chave primária da linha em que 
    // foi gerado o comando no 
    // banco de dados
    unsigned long int idCmd; 
    // Comando a ser executado
    int cmd; 
    // Valor do comando
	char valor[30]; 
    // Bytes de validação do pacote
    unsigned short crc;    
}TPacketResponse;

O alimentador recebendo este pacote, o trata e realiza ou não o comando. Então retorna ao servidor um PACKET CMD RESPONSE, o qual levará as informações inerentes do comando recebido.

typedef struct{
    TPacketInit init;
    TPacketID pid;
    // Rertorna a chave primaria recebida
    unsigned long int idCmd;
    // Retorna o comando recebido 
    int cmd;
    // 0: Comando executado 
    // 1: Comando não executado
    int cmdStatus;
    // Bytes de validação do pacote 
	unsigned short crc;
}TPacketCmdResponse;

O servidor recebendo este pacote, atualiza a tabela outgoing, gerando um timestamp para esta ação.

Registro Usuário

Para se registrar no site o usuário deverá possuir um SERIAL NUMBER válido de um alimentador que não tenha sido cadastrado. Estes dados são guardados na tabela devices:

CREATE TABLE `device` (
	`sn` VARCHAR(10) NOT NULL,
	`id_usuario` INT(11) NOT NULL,
	`datahora` DATETIME NOT NULL,
	PRIMARY KEY (`sn`)
);

Usuário solicita informações do alimentador

Ao logar no site, o usuário é direcionado para um dashboard, onde terá diversas informações sobre o alimentador. Estas informações são provenientes da tabela incoming, sempre solicitando o último registro do banco de dados do seu alimentador.

Usuário envia informações ao alimentador

O usuário, percebendo a necessidade, pode pedir para que o alimentador execute 2 tipos de ação: colocar comida e alterar horário alimentação. Estes comandos são gravados na tabela outgoing, que periodicamente é inspecionada pelo servidor e faz a transmissão ao alimentador.

Síntese do Código Arduino

O código do alimentador foi projetado para ter espaços de tempos pré-definidos para executar ações rotineiras:

  • A cada 10ms: faz a leitura dos botões, atualiza valor quantidade ração disponível, atualiza balança e monta menus localmente quando necessário
  • A cada 1s: atualiza no display porcentagem ração disponível e peso balança
  • A cada 1min: atualiza horário no display e verifica se está no horário para colocar comida
  • A cada 5min: se reporta ao servidor e verifica se possui comandos a serem executados

Os horários de alimentação, quantidade de comida a ser colocada e número de sequência de pacote são gravados na memória EEPROM do Arduino para que as informações não se percam quando houver falta de energia.

Síntese do Código Servidor

A chave para funcionamento do servidor é a utilização do método FORK (disponível para UNIX). Este método permite criar um novo processo idêntico ao processo que o gerou. Sempre que receber um pacote e efetuar sua validação o servidor faz um FORK no processo principal, denominado pai e cria um processo filho, idêntico ao pai. Então o processo filho faz as operações necessárias e se encerra.

A imagem a seguir ilustra o servidor recebendo um pacote, calculando o CRC e realizando o FORK, sendo que a cada FORK realizado o servidor gera um TOKEN para o processo filho, assim pode-se relacionar o momento do FORK com a ação executada pelo processo gerado.

Log gerado no processo pai

Log gerado no processo pai

A imagem a seguir ilustra o processo filho verificando se há mensagem a ser retornada para o alimentador, enviando mensagem e se encerrando.

Log gerado no processo filho

Log gerado no processo filho

A chave para a utilização do método FORK é sempre perguntar aos seus processos filhos como eles estão:

pr=waitpid(-1, &status, WNOHANG);
if(pr == -1){
    log_debug("No forked child, waitpid=%d", pr);
}

Caso não haja este tipo de interação entre processo pai e processo filho, sempre que o processo filho se encerrar, ele irá se encontrar em modo ZOMBIE, ou seja, o processo filho se encerrou, mas ainda continua na memória do computador, aguardando o processo pai se encerrar. Deste ponto em diante há dois processos, no mínimo, sendo executados no servidor, o processo pai, que continua a receber pacotes e o processo filho que trata este pacote recebido.

Criptografia

Buscando por algoritmos de criptografía simétrica (onde utiliza-se a mesma chave para encriptar/desencriptar), encontrou-se diversos métodos consolidados como: AES (Advanced Encryption Standard), DES (Data Encryption Standard), 3DES, RC4, entre outros. O problema em escolher algum desstes está totalmente atrelado ao quanto de memória o dispositivo deve dispor para processar o mesmo. Diante desta questão, entendeu-se que seria inviável utilizar os métodos criptográficos encontrados, e sim, criar um método próprio e simples, o qual foi feito e batizado de Cry Tiger.

A operação básica de um método de criptografia é embaralhar uma mensagem, transmiti-la e poder desembaralhar a mesma sem perder ou ter seu conteúdo alterado. Um modelo simples de criptografia é a Cifra de César, o qual serviu de base para a concepção do Cry Tiger. O modelo de César, é um tipo de cifra de substituição na qual cada letra do texto é substituída por outra, que se apresenta no alfabeto abaixo dela um número fixo de vezes. Por exemplo, com uma troca de três posições, A seria substituído por D, B se tornaria E, e assim por diante. O nome do método é em homenagem a Júlio César, que o usou para se comunicar com os seus generais.

Cifra de César

Cifra de César

Texto cifrado com base no modelo de César

Texto cifrado com base no modelo de César

O método implementado utiliza a operação XOR (OU Exclusivo) como forma de substituição, onde a tabela verdade XOR é apresentada abaixo:

Tabela verdade XOR

Tabela verdade XOR

Portanto, o algoritmo deverá ter um buffer para armazenar o conteúdo a ser encriptado e um buffer contendo uma chave que servirá para realizar a encriptação. Neste modelo pode ser encriptado qualquer tipo de dado, não somente texto. Logo, faz-se a operação XOR de cada elemento do buffer com o elemento de mesmo índice da chave, para se obter o texto encriptado:

Buffer plaintext    31  32  33  34  35 
Buffer chave 	    FF  AE  22  31  43 
  	                    XOR 
Buffer encriptado   CE  9C  11  5   76 

O mesmo vale para quando necessita-se desencriptar um buffer:

Buffer encriptado   CE  9C  11  5   76
Buffer chave 	    FF  AE  22  31  43 
  	                    XOR 
Buffer plaintext    31  32  33  34  35

O buffer a ser encriptado não tem seu tamanho limitado, porém é preciso conhecer o seu tamanho para o processo de encriptação/desencriptação ocorrer.

Para deixar o algoritmo dinâmico, a chave do Cry Tiger pode ter seu tamanho modificado, de acordo com a necessidade do usuário. Isto é definido no header do arquivo:

#define LEN_XORKEY 32

Possui um método para expandir a chave utilizada para o seu tamanho máximo. Isto é necessário quando por exemplo, usuário cria uma chave: “12345” mas a mesma é de tamanho máximo de 16 bytes, logo ela será expandida para “1234512345123451”.

void TCrytiger::InitTiger(
    unsigned char *key,
    int lenKey)
{
    int index=0;
    memset(XorKey, 0, LEN_XORKEY);

    while(index < LEN_XORKEY){
        if(LEN_XORKEY-index > lenKey){
            memcpy(&XorKey[index], 
                   key, 
                   lenKey);
            index+=lenKey;
        }
        else{
            memcpy(&XorKey[index], 
                   key, 
                   LEN_XORKEY-index);
            break;
        }
    }
}

Com a chave já expandida, realiza-se a encriptação/desencriptação utilizando a operação XOR, pelo método a seguir, independentemente do tamanho do buffer a ser recebido:

void TCrytiger::EncryptDecrypt(
    unsigned char *inpString, 
    int len)
{
    int index=0;
    for(int i = 0; i < len; i++){
        if(index >= LEN_XORKEY){
            index=0;
        }
        inpString[i] = 
            inpString[i] ^ XorKey[index];
        index++;
    }
}

Resultados


O alimentador automático realizou as funções de dispensa do alimento nos horários pré-determinados de forma eficiente em 98,7% dos casos, o que indicou um alto nível de eficiência para a função principal que o qual foi desenvolvido. A quantidade de ração presente no dispensador apresentou uma porcentagem de exatidão de aproximadamente 80%, apesar de alto valor este índice pode ser melhorado através do uso de sensores mais precisos, a quantidade de alimento mensurada através do sensor de carga se mostrou de baixa eficiência sendo que o modelo utilizado não foi o mais apropriado para o projeto em questão.

Considerações Finais


O uso de aparelhos de automação contribui de forma significativa para uma melhor qualidade de vida dos seus usuários neste contexto o PetFeeder se mostrou eficiência para garantir a alimentação regular do pet, de forma que pode vir a evitar doenças decorrentes da má nutrição ocasionada pela forma de vida dos seus tutores que não encontram tempo hábil na garantia de fornecer uma alimentação adequada ao seu animal.