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
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
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 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
Rosca sem fim
Balança
Componentes Eletrônicos
Os componentes eletrônicos a seguir constituem o PetFeeder:
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
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
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
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
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
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
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.