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.