INSTITUTO FEDERAL DO ESPÍRITO SANTO
PÓS-GRADUAÇÃO LATO SENSU EM ENGENHARIA ELÉTRICA COM ÊNFASE
EM SISTEMAS INTELIGENTES APLICADOS À AUTOMAÇÃO
ZOROASTRO SANTOLIM PIMENTA
CONTROLE DOS MOVIMENTOS DE UM SISTEMA CARTESIANO PARA
LOCALIZAÇÃO DE OBJETOS COM USO DE REALIMENTAÇÃO POR IMAGEM
Vitória
2014
ZOROASTRO SANTOLIM PIMENTA
CONTROLE DOS MOVIMENTOS DE UM SISTEMA CARTESIANO PARA
LOCALIZAÇÃO DE OBJETOS COM USO DE REALIMENTAÇÃO POR IMAGEM
Monografia apresentada ao Curso de
Pós-Graduação
Lato
Sensu
em
Engenharia Elétrica com Ênfase em
Sistemas Inteligentes Aplicados à
Automação do Instituto Federal do
Espírito Santo como requisito parcial
para obtenção do certificado de
Especialista em Sistemas Inteligentes
Aplicados à Automação.
Orientador: Prof. M. Sc. Paulo Henrique
F. Zanadrea
Vitória
2014
(Biblioteca Nilo Peçanha do Instituto Federal do Espírito Santo)
P644c Pimenta, Zoroastro Santolim.
Controle dos movimentos de um sistema cartesiano para
localização de objetos com uso de realimentação por imagem /
Zoroastro Santolim Pimenta. – 2014.
45 f. : il. ; 30 cm
Orientador: Luis Eduardo Martins de Lima.
Monografia (especialização) – Instituto Federal do Espírito
Santo, Coordenadoria de Pós-Graduação em Engenharia
Elétrica, Curso Pós-Graduação Lato Sensu em Engenharia
Elétrica com Ênfase em Sistemas Inteligentes Aplicados à
Automação, 2014.
1. Visão por computador. 2. Sistemas de controle por
realimentação. 3. Processamento de imagens. 4. Engenharia
elétrica. I. Lima, Luis Eduardo Martins de. II. Instituto Federal
do Espírito Santo. III. Título.
CDD 21 – 006.37
Dedico este trabalho primeiramente à Deus, que me deu a graça de estar aqui,
também à minha família que durante o período deste curso precisou tolerar a minha
ausência. Também aos meus amigos e colegas de curso, pois passamos juntos por
todas as situações sempre com otimismo e companheirismo.
AGRADECIMENTOS
Agradeço a todos que contribuíram para a realização deste trabalho, em especial ao
Bruno por ter cedido o material e aos professores por terem ensinado os conteúdos
tão importantes para a realização deste, em especial ao meu orientador, por ter tido a
paciência de sempre me apoiar durante estes meses de trabalho.
RESUMO
A visão computacional é definida como a construção de descrições explícitas e
significativas de objetos físicos a partir de imagens. A utilização da visão
computacional como ferramenta de um sistema de controle é o assunto deste
trabalho, juntamente com o desenvolvimento de um sistema de controle de uma mesa
XY e um cabeçote que se movimenta sobre ela, baseado em identificação de objetos
através de suas cores. Também é objetivo deste trabalho embarcar toda a solução
em uma plataforma de processamento computacional miniaturizada e autônoma,
agregada à mesa XY.
Palavras chave: Beaglebone. Controle. Embarcado. Processamento Digital de
Imagens. Visão Computacional. Controle de Movimento de um Cabeçote Cartesiano.
ABSTRACT
Computer vision is defined as the construction of explicit and significant descriptions
of physical objects on images. The use of computer vision as a control system
feedback tool is the subject of this paper, along with the development of a control for
an XY table and a moving head that is mounted on it, using color based object
identification. It is also subject of this paper embed the complete solution in one small
and autonomous processing platform, attached to the XY table.
Keywords: Beaglebone. Control. Embedded. Digital Image Processing. Computer
Vision. Control of a Cartesian Moving Head’s Position.
SUMÁRIO
1
INTRODUÇÃO ................................................................................................... 9
2
PROCESSAMENTO DIGITAL DE IMAGENS .................................................. 10
3
VISÃO COMPUTACIONAL .............................................................................. 11
4
O MODELO PINHOLE ..................................................................................... 12
5
O PROBLEMA ................................................................................................. 14
6
DESENVOLVIMENTO ...................................................................................... 16
6.1
RECURSOS INICIAIS ...................................................................................... 16
6.2
CONSTRUÇÃO E ADEQUAÇÃO FÍSICA/MECÂNICA .................................... 16
6.3
ADEQUAÇÃO ELETRÔNICA........................................................................... 17
6.4
CONTROLE DOS MOTORES DOS EIXOS ..................................................... 19
6.5
ALGORITMO DE CAPTURA DE IMAGENS .................................................... 20
6.6
ESCOLHENDO O ALVO E O MARCADOR DO CABEÇOTE .......................... 22
6.7
IDENTIFICANDO O ALVO E O MARCADOR .................................................. 23
6.8
ALGORITMO DE FILTRAGEM DE CORES ..................................................... 24
6.9
DESCOBRINDO O CENTRO DO OBJETO ..................................................... 26
6.10 O PROBLEMA DO MODELO PINHOLE .......................................................... 28
6.11 SOLUÇÃO ADOTADA PARA O PROBLEMA DO MODELO PINHOLE ........... 29
6.12 MINIATURIZANDO E EMBARCANDO TODA A SOLUÇÃO............................ 32
7
RESULTADOS ................................................................................................. 35
8
CONCLUSÃO E TRABALHOS FUTUROS...................................................... 36
REFERÊNCIAS ................................................................................................ 37
APÊNDICE A ................................................................................................... 38
Códigos FONTE para controle dos motores de passo ..................................... 38
APÊNDICE B ................................................................................................... 42
Códigos FONTE para identificação de objetos pela webcam ........................... 42
9
1 INTRODUÇÃO
Tentar, errar e consertar são funções básicas de qualquer sistema de controle, seja
ele eletrônico, mecânico ou até biológico.
Neste trabalho são colocados em prática várias áreas de conhecimento com um
objetivo: o controle de um cabeçote em uma mesa XY, utilizando visão computacional.
Durantes as seções de 2 a 5 são discutidos alguns conceitos, apenas para
contextualizar o trabalho e também ressaltar a sua importância, transformando em
prática os conhecimentos adquiridos em sala de aula.
A partir da seção 6.1 são apresentadas passo a passo cada uma das atividades
realizadas para a implementação e conclusão do trabalho proposto. Ao final são
discutidas algumas possibilidades para a modificação e utilização do resultado
alcançado de outras formas e em busca de outros objetivos.
10
2 PROCESSAMENTO DIGITAL DE IMAGENS
Dentre os 5 sentidos fundamentais para os seres humanos, em geral, o que mais se
destaca na nossa percepção do mundo, é o sentido da visão. A luz que é refletida
pelos objetos que nos cercam chega até os nossos olhos, que por sua vez, traduzem
as informações luminosas em outro tipo de informações, as quais são transmitidas
para o cérebro.
Não é por acaso que este é o mais desenvolvido dos 5 sentidos. É inicialmente pela
visão que conseguimos detectar a distância de algum objeto, podemos determinar se
este mesmo objeto está parado ou em movimento, nos orientamos através de
marcações ou caminhos detectados através da visão, além de ser uma das
realimentações para o controle do corpo humano. É através da visão que
conseguimos diminuir a velocidade ao aproximar as mãos para apanhar um objeto,
ao invés de derrubá-lo.
Uma foto é um registro instantâneo de um momento, um acontecimento, uma
situação. Sendo assim, utilizar a visão como um meio para a obtenção de informações
do mundo é um recurso natural para nós. E com os recursos computacionais atuais,
obter informações a partir de imagens se torna uma tarefa computacional factível.
Uma imagem (em tons de cinza) é definida como uma função de duas dimensões, f(x,
y), onde x e y são coordenadas espaciais e o valor de f em qualquer par de
coordenadas (x, y) é chamado de intensidade ou nível de cinza da imagem naquele
ponto. Quando x, y e f tem valores finitos e discretizados, a imagem é então chamada
de imagem digital (GONZALEZ, 2011).
Em uma imagem digital, cada par de coordenadas (x, y) recebe o nome de elementos
de imagem (em inglês, picture elements ou pixels). O termo mais comum para definir
um elemento de imagem digital é o Pixel.
Derivado do campo de processamento digital de sinais, o processamento digital de
imagens é a utilização de computadores digitais para o processamento de imagens
digitais, onde tanto as informações de entrada do processo, quanto as informações
resultantes, são imagens (GONZALEZ, 2011).
11
3 VISÃO COMPUTACIONAL
A habilidade humana em extrair informações a partir do seu sistema visual se
desenvolve desde o nascimento, através de um processo contínuo de identificação –
extração – armazenamento.
As imagens projetadas na metade esquerda da retina de cada olho são enviadas para
o córtex visual primário do hemisfério esquerdo do cérebro, enquanto que as imagens
projetadas na metade direita da retina de cada olho são enviadas para o córtex visual
primário do hemisfério direito. Como as imagens projetadas na retina são invertidas,
cada hemicampo visual é trabalhado no lado oposto do cérebro, ou seja, o hemicampo
visual direito é trabalhado no centro visual esquerdo e o hemicampo visual esquerdo
é trabalhado no centro visual direito do cérebro (GUIMARÃES, 2004).
Apesar de toda a complexidade envolvida, a velocidade com que conseguimos
identificar um objeto a partir de uma imagem é incrivelmente rápido e todo este
processamento acontece em uma das áreas mais complexas do cérebro: o córtex
visual.
Cientistas e pesquisadores dedicam seus esforços em tentar desenvolver sistemas
capazes de imitar a maneira como o sistema visual humano trabalha, desde os
primeiros experimentos na década de 1950 (BALLARD, 1982).
Ballard e Brown (BALLARD, 1982) definem a visão computacional como a construção
de descrições explícitas e significativas de objetos físicos a partir de imagens.
Em visão computacional o objetivo é bem diferente do processamento de imagens,
onde ambos o insumo e o produto do processo são imagens, mas sim prover a uma
máquina, a capacidade de perceber as informações contidas nestas imagens, sendo
um pré-requisito para reconhecer, manipular e até pensar sobre os objetos ali
presentes.
O campo da visão computacional tem sido amplamente explorado em vários
segmentos, como por exemplo na medicina, com diagnósticos por imagem. Também
em aplicações militares, sendo usado como mecanismos de detecção de inimigos.
Mais áreas incluem a indústria, exploração espacial, sistemas de controle, controle de
crescimento de áreas de desmatamento, poluição, entre outras.
12
4 O MODELO PINHOLE
Para uma máquina conseguir extrair informações de uma imagem, antes é necessário
que esta imagem seja capturada, seja através de câmeras fotográficas, scanners,
câmeras de vídeo ou outros.
Os dispositivos que mais se assemelham aos olhos humanos, capturando imagens
rapidamente, são as câmeras e inclusive existem alguns modelos de projeção
disponíveis que mapeiam matematicamente a relação entre as coordenadas de um
ponto tridimensional no campo de visão da câmera, com sua projeção bidimensional
no plano da imagem.
Um modelo que é amplamente aplicado para o mapeamento e calibração de câmeras
é o modelo pinhole. Este modelo é baseado na idéia de que toda a luz disponível para
contribuir com a geração da imagem, deve passar através de um orifício (o centro
ótico da câmera), cujo diâmetro é muito próximo a zero, como representado na figura
1. O modelo pinhole também é utilizado para explicar o funcionamento de câmaras
estenopeicas.
Figura 1 - Representação de um modelo pinhole, ou câmara estenopeica
Fonte: http://en.wikipedia.org/wiki/Pinhole_camera
Figura 2 - Modelo ideal de câmera pinhole
Fonte: (ALMONFREY, 2013)
13
Utilizando o modelo representado pela figura 2, é possível mapear o caminho de um
raio sendo refletido pelo ponto p, atravessando o centro ótico da câmera, o ponto o e
terminando no plano de projeção, no ponto p’. A imagem completa é apresentada
invertida no plano de projeção, algo como acontece na retina humana.
O ponto 𝑝 = [𝑋, 𝑌, 𝑍]𝑇 possui imagem 𝑝′ = [𝑥, 𝑦]𝑇 , sendo 𝑓 a distância focal
(distância entre o plano de projeção e o centro ótico) da câmera.
Através da semelhança de triângulos é possível mapear as igualdades das projeções
(ALMONFREY, 2013):
𝑋
𝑍
𝑌
𝑦 = −𝑓
𝑍
𝑥 = −𝑓
(1)
(2)
14
5 O PROBLEMA
No início deste trabalho, desejava-se unir conhecimentos em várias áreas de estudo,
como visão computacional, processamento de imagens, sistemas embarcados,
programação avançada, sistemas de controle e inteligência artificial para a construção
de uma solução prática.
Primeiramente foi necessário identificar um problema, ao qual uma solução prática e
englobando a maioria das áreas acima descritas, se encaixasse.
Havia uma mesa construída em alumínio e teflon, a qual estava disponível, com dois
motores de passo bipolares, cada um com características de alimentação e ângulo de
passo diferentes. Cada um destes motores movimentava uma correia, um para o eixo
X e outro para o eixo Y, uma imagem da mesa, inicialmente, era como a da Figura 3.
Quando os motores são acionados, as correias de cada eixo movimentam um
cabeçote (elemento final) dentro da área de atuação da mesa.
Figura 3 - Foto inicial da mesa X Y
Fonte: Autor, 2014
Também já estavam montados e disponíveis na mesa os circuitos para acionar os
motores de passo.
O problema é identificar e localizar um objeto na área de atuação da mesa XY.
15
Apenas a título de inspiração, vale a pena citar outros trabalhos que alcançaram
objetivos multidisciplinares como o deste trabalho. Como um exemplo, um trabalho
realizado utilizando visão computacional onde um quadrirotor é observado por
câmeras e todo o processamento do seu controle é realizado em um tablet conectado
ao sistema (JEONGWOON Kim, 2013).
Outro exemplo é o controle de um braço robótico utilizando visão computacional,
realizado por estudantes em uma univerdade na Espanha (CABRE, T.P., 2013), a
aplicação de visão para ampliar a percepção sensorial de robôs executando tarefas
(PAPANIKOLOPOULOS, N.P., 1995), controle de maquinários pesados
(GARIBOTTO, G., 1997) e até um manipulador aquático (SMITH, J.S., 1994).
Não foram encontrados, durante as pesquisas feitas, trabalhos com escopo mais
semelhante ao deste, porém os trabalhos encontrados na área de visão
computacional serviram de inspiração para este desenvolvimento.
16
6 DESENVOLVIMENTO
6.1 RECURSOS INICIAIS
Para este trabalho, os recursos utilizados foram:

A mesa X Y, como descrita anteriormente, juntamente com seu circuito
acionador para os motores de passo;

Fonte 12V e 5V, para alimentar as interfaces de controle dos motores de passo,
a câmera e outros circuitos eletrônicos;

Webcam modelo WC040 da marca Multilaser, com sensor de 300K pixels para
vídeo;

Arduino Uno R3, para testar e controlar as interfaces com os motores;

IDE Arduino 1.0;

Computador tipo PC, para realizar a programação, testes e verificações dos
algoritmos gerados;

Sistema Operacional Windows 7;

Mathworks MatLab, versão Student 2012a;

Ambiente de programação IDE Eclipse, para a programação dos algoritmos de
visão computacional;

Biblioteca de código aberto para visão computacional OpenCV, versões 2.1.0
e 2.4.1;

Compiladores GNU C e GNU C++ versões 4.4 e 4.6 em ambientes Linux e
Windows.

BeagleBone White (256MB RAM, 700MHz CPU);

Peças de cantoneira em alumínio.
6.2 CONSTRUÇÃO E ADEQUAÇÃO FÍSICA/MECÂNICA
Um dos primeiros testes realizados, foi para confirmar que toda a estrutura mecânica
estava funcionando corretamente: se os motores realmente movimentavam a correia
e também se a correia movimentava o carrinho. Portanto desta maneira, também foi
testada a parte eletrônica, os circuitos acionadores dos motores de passo.
Definir a posição da câmera foi o passo seguinte. Com a câmera conectada ao
computador, foi utilizado um programa de visualização nativo do sistema operacional
para capturar imagens em tempo real.
17
Este teste foi necessário para se conseguir definir em qual altura, a partir do plano da
mesa XY, a imagem gerada pela câmera capturava toda a área de movimentação do
cabeçote. Foi necessário colocar a câmera a uma altura de 1,2m a partir do plano da
mesa, para que toda a mesa fosse capturada nas imagens geradas.
Para manter a câmera nesta posição, optou-se por uma fixação com armação do tipo
tripé. Esta armação foi construída com cantoneiras de alumínio e fixada nas arestas e
laterais da mesa. O resultado pode ser verificado na Figura 4, abaixo:
Figura 4 - Foto da fixação da câmera na mesa XY
Fonte: Autor, 2014
6.3 ADEQUAÇÃO ELETRÔNICA
Os circuitos de acionamento dos motores de passo, originalmente eram formados por
2 controladores separados, cada um contendo um CI L297 e um CI L298, ambos
sincronizados por uma fonte de clock formada por um circuito com um CI 555.
O CI L297 é o responsável por gerar os sinais de fase para controle dos motores de
passo e pode ser utilizado para controlar unipolares e bipolares (4 fases em um motor
unipolar ou 2 fases em um motor bipolar) (STMICROELECTRONICS, 2001). Já o CI
L298 é um controlador de potência, que contem encapsuladas, 2 pontes H, servindo
para controlar 2 motores DC comuns ou 1 motor de passo (STMICROELECTRONICS,
2000).
Para esta aplicação, um dos requisitos definidos era o de total autonomia do algoritmo
de visão computacional, que estaria sendo executado no computador, sobre o
18
acionamento dos motores. Portanto foi preciso remodelar o circuito de controle,
mantendo o CI de potência L298, para acionamento das fases dos motores, porém
removendo o CI L297 e também o CI 555.
No lugar do controlador removido, optou-se em utilizar uma solução que integrasse
algum tipo de comunicação com a plataforma PC. A escolha do Arduino Uno R3 para
realizar esta tarefa foi trivial, pela boa disponibilidade, documentação e preço da placa.
O Arduino comunica-se com o PC através da porta USB, enviando e recebendo
informações do computador via protocolo de transmissão serial. Outras opções de
micro controladores foram analisadas, mas a solução adotada inicialmente foi a que
estava imediatamente disponível, além de contar com muitas bibliotecas de código
fonte aberto e exemplos disponíveis na internet. Foi utilizada a biblioteca nativa do
sistema para controle de motores de passo.
A Figura 5 mostra como foi montada a interface de controle para apenas um, dos dois
motores de passo utilizados no sistema. Para a representação completa do circuito de
testes, considerar a utilização de 2 CIs L298, um para cada motor, conectadas ao
mesmo Arduino controlador. Observe que os diodos de proteção foram
desconsiderados na montagem da Figura 5, mas todo o procedimento montado
fisicamente seguiu as instruções do manual do CI (STMICROELECTRONICS, 2000),
conforme diagrama esquemático da Figura 6.
Figura 5 - Controle de um motor de passo utilizando Arduino
Fonte: Autor, 2014
19
Figura 6 - Diagrama esquemático de controle de um motor de passo
Fonte: http://www.hoelscher-hi.de acessado em 31/05/2014
6.4 CONTROLE DOS MOTORES DOS EIXOS
Como mencionado anteriormente, foi utilizado o Arduino UNO R3 para o controle
inicial dos motores de passo instalados na mesa, principalmente pela facilidade e
rapidez para a geração de um protótipo funcional.
O ambiente de programação do Arduino conta com uma biblioteca já instalada para
controle de motores de passo, monopolares e bipolares. Esta biblioteca se chama
Stepper.
O programa de controle inicial, ainda sem a interação com o PC, executava duas
funções básicas essenciais: a primeira era manter os motores parados e por
consequência o cabeçote também não se movimentava. A segunda era movimentar
cada motor para frente e para trás. Seguindo uma ordem específica, o movimento
gerado no cabeçote era quadricular e sempre retornava ao ponto de origem.
Estas duas funções exercidas pelo sistema de controle inicial tornavam outros
desenvolvimentos e testes possíveis. Com os motores parados, era possível
desenvolver o algoritmo necessário para capturar as imagens e filtrar apenas a
posição do cabeçote e também somente a posição do alvo. Com os motores em
movimento era possível gerar o algoritmo que acompanhava o percurso do cabeçote,
quadro a quadro do vídeo, conforme apresentado na figura 7.
20
Figura 7 – Movimentação inicial do cabeçote
Fonte: Autor, 2014
6.5 ALGORITMO DE CAPTURA DE IMAGENS
Dentre algumas ferramentas de software para visão computacional, de código fonte
aberto disponíveis na Internet, procurou-se utilizar a que contivesse uma boa
documentação, suporte e grande número de exemplos.
A biblioteca OpenCV (Open Computer Vision) é uma ferramenta modular que atende
aos requisitos acima, com código fonte aberto com licença BSD e contendo centenas
de algoritmos voltados para visão computacional.
Alguns algoritmos disponíveis no OpenCV são voltados especificamente para
atividades como (OPENCV DEV TEAM, 2013):

Captura de vídeo (módulo vídeo);

Processamento de Imagens (módulo imgproc);

Calibração de sistemas de visão 3D (módulo calib3d);

Detecção de objetos (módulo objdetect);

Geração de interfaces gráficas (módulo highgui);

Entre outras (módulos core, features2d, gpu, etc.).
Através da documentação e utilizando o módulo de vídeo do OpenCV, tornou-se viável
capturar a imagem da câmera, tendo a webcam conectada ao PC e um programa com
uma função principal contendo as linhas abaixo:
#include "cv.h"
...
CvCapture* capture = 0;
capture = cvCaptureFromCAM( 0 );
IplImage* frame = cvQueryFrame( capture );
21
De acordo com o manual, a partir deste ponto do programa, uma imagem capturada
da câmera, estará armazenada na variável frame. Se isto for feito sucessivas vezes,
teremos uma sequência de imagens, ou seja, um filme.
Este algoritmo foi testado em um PC executando o sistema operacional Windows 7 e
a captura da imagem foi comprovada.
As figuras 8 e 9 ilustram alguns exemplos de imagens que foram capturadas durante
o processo de desenvolvimento, utilizando o mesmo algoritmo:
Figura 8 – Captura para tentativa de calibração
Fonte: Autor, 2014
Figura 9 – Captura do cabeçote
Fonte: Autor, 2014
22
6.6 ESCOLHENDO O ALVO E O MARCADOR DO CABEÇOTE
Uma vez que o programa em desenvolvimento já tem a habilidade de colher imagens
que estão sendo geradas pela câmera, o próximo passo é escolher o alvo e também
conseguir identificar a posição do cabeçote, para que assim possamos movimentar o
cabeçote até a posição do alvo.
Escolher o alvo e o marcador do cabeçote é uma tarefa importante e que necessita
de uma análise delicada. É a partir desta escolha que poderá ser definido o tipo de
algoritmo necessário para realizar a detecção dos objetos.
Existem muitas formas de se identificar um objeto em uma imagem e o OpenCV tem
ferramentas para muitas destas (OPENCV DEV TEAM, 2013). Objetos podem ser
identificados por:

Seu formato: quadrado, redondo, triangular, etc.;

Sua cor;

Características da imagem, como tamanho, orientação, histograma;

Treinamento e comparação com um banco de dados de objetos conhecidos;

E possivelmente outras características mais.
Para cada tipo de identificação existe um grau de complexidade envolvida no
algoritmo. Sendo assim, optou-se pela utilização do método com a menor
complexidade: identificar os objetos através de suas cores:
Prós:

Poderá ser utilizado qualquer formato de objeto;

Será identificado independentemente de sua posição, orientação, tamanho,
etc.;

Não haverá a necessidade de treinamento e nem a composição de um banco
de dados para a comparação;

Algoritmo simples.
Contras:

Só poderá haver um objeto de cada cor;

O resto da imagem deve ser de cores diferentes das já escolhidas;

A eficiência da detecção pode variar com a intensidade e cor da luz à qual os
objetos estão expostos;
23
6.7 IDENTIFICANDO O ALVO E O MARCADOR
Já definida a forma de identificação dos objetos, escolheu-se as cores separadamente
para o alvo e o cabeçote, de forma empírica: havia um ruído de cor nas imagens
geradas pela câmera, talvez pela qualidade da mesma, que poderia prejudicar a
identificação de algumas cores. Monitorando as imagens geradas, eram colocados
diversos objetos com cores variadas e daí observadas quais as cores que geravam
menos ruídos.
Para o alvo, foi escolhida a cor verde (Figura 11) e para o cabeçote, foi escolhida a
cor vermelha. Desta maneira, não poderia haver na imagem nenhum outro objeto com
as mesmas cores. Na figura 10 pode-se ver uma ilustração contendo os objetos em
suas cores:
Figura 10 – Captura da câmera, mostrando o cabeçote em vermelho e o alvo em
Fonte: Autor, 2014
A figura 11 apresenta a imagem do objeto usado como alvo.
Figura 11 – Objeto usado como alvo
Fonte: Autor, 2014
verde
24
6.8 ALGORITMO DE FILTRAGEM DE CORES
A informação sobre a cor de um ponto em uma imagem pode ser representada de
diversas maneiras, dependendo somente de qual Espaço de Cores (chamado também
de Sistema de Cores ou Modelo de Cores) está sendo utilizado (GONZALEZ, 2011).
Por exemplo, no espaço de cores RGB, uma cor é representada pela mistura das
cores primárias vermelho, verde e azul (Red, Green e Blue). Em outro espaço, o
CMYK, a mesma cor é representada pela mistura das cores ciano, magenta, amarelo
e preto (Cyan, Magenta, Yellow e Black).
Dentro do Modelo RGB, também é possível mapear a variação da mistura das cores
primárias que gerarão a nova cor de muitas maneiras. Uma destas maneiras é a
representação HSV (Hue, Saturation e Value). Dentro do HSV é possível representar
uma cor através de parâmetros de matiz (hue), saturação e valor (também interpretado
como brilho). A matiz representa o tipo de cor, ou seja, vermelho, azul, amarelo,
violeta, etc. A saturação representa a pureza da cor, quanto menor a pureza, mais
cinza será a cor. O parâmetro Value (valor) define o brilho da cor.
A figura 12 mostra como representar as cores vermelha e verde em RGB e HSV.
Utilizando este mapeamento de cores para trabalhar em nossas imagens, é possível
e de forma simples, separar os pontos de uma determinada cor ou faixa de cores e é
exatamente o que é preciso para identificar o alvo e o cabeçote.
Figura 12 – Representação das cores vermelha e verde em RGB e HSV
Fonte: http://www.rapidtables.com/convert/color/rgb-to-hsv.htm em 31/05/2014
Através da Figura 12 fica simples perceber a vantagem em utilizar a representação
HSV. Para variar da cor vermelha para a cor verde, foi necessário mudar apenas o
valor de H, de 0 para 120. Os valores de saturação e valor continuaram os mesmos
para ambas as cores. Já na representação RGB foram necessárias alterações em
dois dos três parâmetros (R e G).
25
Todas as imagens capturadas pela câmera, utilizando o algoritmo discutido na seção
6.5 deste trabalho, tem as suas cores representadas em RGB e portanto, precisam
ser convertidas para a representação HSV para que seja mais fácil a separação das
cores que queremos identificar.
Uma operação onde a entrada é uma imagem e a saída é outra imagem é uma
operação de processamento de imagens. O OpenCV oferece uma função para a
conversão entre estas representações:
Primeiro é necessário criar uma imagem vazia para receber o resultado da função.
Em seguida utilizar a função cvCvtColor que recebe a imagem original, realiza a
conversão para HSV (utilizando o parâmetro CV_BGR2HSV) e salva o resultado na
nova variável.
IplImage* imgHSV = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3);
cvCvtColor(frame, imgHSV, CV_BGR2HSV);
Agora que o programa já tem as informações de todas as cores da imagem, é
necessário realizar uma filtragem de cores, para que somente a cor de interesse seja
mostrada. Todas as outras cores devem ser apagadas da análise, ou seja, neste caso,
transformadas na cor preta.
No OpenCV, uma função que realiza este processamento é cvInRange. Esta função
recebe como entrada a imagem, duas faixas de cores e também a imagem para onde
ela deve salvar o resultado. As faixas de cores, definidas em seus parâmetros, são as
informações que realizam o filtro. A imagem resultado é formada apenas por pontos
pretos e brancos, ou seja, é uma imagem binarizada. Os pontos em preto são pontos
onde na imagem original representavam cores que estavam fora das faixas definidas.
Já os pontos em brancos representam as cores que pretencem à faixa das cores
desejadas.
Definir as faixas para filtrar o verde e o vermelho dos objetos que precisamos
identificar foi outra tarefa empírica, variando as faixas de valores de H, S e V até que
somente o objeto na cor de interesse estivesse à mostra na imagem. Para isto, foi
utilizado o MatLab 2012a e em seguida um software disponível nos exemplos da
documentação do OpenCV para filtragem HSV. Um exemplo é o da imagem
representada na figura 13:
26
Figura 13 – Filtragem de cores
Fonte: Autor, 2014
Definidas as faixas de composição das cores do alvo e do cabeçote, aplicamos a
função cvInRanges, salvando o resultado em uma nova imagem:
IplImage* imgThresh=cvCreateImage(cvGetSize(imgHSV),IPL_DEPTH_8U, 1);
cvInRangeS(imgHSV, cvScalar(lowerH,lowerS,lowerV), cvScalar(upperH,upperS,upperV),
imgThresh);
Este procedimento deve ser executado separadamente para encontrar e filtrar para
uma imagem, somente o alvo e para outra imagem, somente o cabeçote. No final,
teremos duas imagens parecidas com a imagem da direita na Figura 13.
Variação possível para os parâmetros, no OpenCV:
(0 ≤ H ≤ 180); (0 ≤ S ≤ 255); (0 ≤ V ≤ 255).
Apenas para referência, as faixas adotadas para filtragem foram:
Para o cabeçote (vermelho):
(170 ≤ H ≤ 180); (108 ≤ S ≤ 255); (100 ≤ V ≤ 255);
Para o alvo (verde):
(69 ≤ H ≤ 95); (85 ≤ S ≤ 143); (0 ≤ V ≤ 255);
Por se tratar de uma faixa de valores, a detecção apresenta uma certa tolerância
quanto a variação de iluminação e cor dos objetos. Repare que na Figura 13, apesar
de o reflexo da tampa na mesa também ser de tom esverdeado, este tom está fora da
faixa de filtragem e não está sendo considerado.
6.9 DESCOBRINDO O CENTRO DO OBJETO
O resultado da seção 6.8 é formado por duas imagens em preto e branco. Cada uma
contendo vários pontos possivelmente próximos a um ponto central.
27
O objetivo agora é determinar qual é este ponto central, pois se não houverem outros
objetos de cores semelhantes presentes na imagem, este ponto também será o centro
do objeto.
Momentos de uma imagem são quantidades escalares utilizadas para caracterizar
uma função (imagem) e capturar suas características mais significativas (FLUSSER,
2009).
Neste trabalho foram utilizados apenas três momentos, que caracterizam o centro de
massa dos pontos brancos da imagem. Um para o eixo X, outro para o eixo Y e o
terceiro que obtinha a área do objeto. Para o programa em desenvolvimento, a
maneira de obter estes dois momentos está descrita no código abaixo:
CvMoments *moments = (CvMoments*)malloc(sizeof(CvMoments));
cvMoments(imgThresh, moments, 1);
double M10 = cvGetSpatialMoment(moments, 1, 0);
// Momento do eixo X
double M01 = cvGetSpatialMoment(moments, 0, 1);
// Momento do eixo Y
double Area = cvGetCentralMoment(moments, 0, 0); // Momento da área M00
// Captura a posição da centróide do objeto, baseado nos momentos da imagem binarizada
posX = (M10/Area);
posY = (M01/Area);
Maiores detalhes sobre a função cvMoments podem ser encontrados na
documentação da biblioteca OpenCV (OPENCV DEV TEAM, 2013), porém o
importante a ser considerado aqui é que o resultado do código acima, sendo utilizado
para processar as imagens em preto e branco do cabeçote e do alvo, é que
conseguimos a posição central destes objetos na imagem, em valores de pontos
(pixels).
Na Figura 14, linha vermelha mostra a posição do cabeçote e a linha azul do alvo.
Figura 14 – Identificando a posição dos objetos automaticamente
Fonte: Autor, 2014
28
6.10 O PROBLEMA DO MODELO PINHOLE
Consideremos novamente as equações (1) e (2) da seção 4:
𝑋
𝑌
Se 𝑥 = −𝑓 𝑍 e 𝑦 = −𝑓 𝑍 , observamos que
𝑋
𝑍
e
𝑌
𝑍
são proporções. Se mantivermos a
proporção, variando o valor de Z e os valores de X e Y, teremos como resultado de
(1) e (2) os mesmos 𝑥 e 𝑦.
Isto é: se aumentarmos a distância de um objeto para a câmera e também
aumentarmos sua posição X e Y em relação ao centro ótico, na mesma proporção, a
posição do objeto na imagem resultante de duas dimensões, é a mesma (Figura 15).
Figura 15 – Diferença de planos
Fonte: Autor, 2014
Observe a Figura 16. Iniciando no ponto A para o cabeçote e no ponto B para o alvo,
não haveria nenhum problema, pois o cabeçote estaria na posição correta para a
câmera, ou seja, estaria acima do alvo. Porém o problema acontece quando o alvo
não está próximo ao centro ótico da câmera.
Figura 16 – Diferença de planos do cabeçote e do alvo
Fonte: Autor, 2014
Se o alvo estiver em B1, a mesa deveria movimentar o cabeçote até o ponto onde ele
estivesse logo acima do alvo e esta seria a posição correta, ou seja, A1. Só que ao
29
invés disto, para a câmera, o cabeçote estará acima do alvo quando sua posição for
A1’.
Para a câmera a vista seria como a da figura 17, seguindo o mesmo posicionamento
de objetos da Figura 16:
Figura 17 – Diferença de planos do cabeçote e do alvo vista da câmera
Fonte: Autor, 2014
Se fossemos utilizar o sistema desta maneira, quando o alvo estivesse fora de
alinhamento direto com o centro ótico da câmera, provavelmente estaríamos atuando
sobre um espaço vazio ou apenas sobre uma beirada do alvo.
6.11 SOLUÇÃO ADOTADA PARA O PROBLEMA DO MODELO PINHOLE
Já temos um modelo representativo da visão da câmera. Mesmo exibindo o problema
acima, se utilizarmos as propriedades de semelhança de triângulos e as fórmulas do
modelo Pinhole, conhecendo a diferença de distância para a câmera dos planos A (do
cabeçote) e B (do alvo), é possível realizar um mapeamento do plano B sobre o plano
A ou vice-versa.
Porém, existe outro problema: a construção da câmera não é perfeita e as imagens
geradas podem não ser também. O centro ótico da imagem pode não ser o mesmo
que o centro da imagem. Pode haver distorções no caminho que a luz percorre através
das lentes até o sensor ótico. O próprio sensor ótico pode estar inclinado ou fora de
centralização com as lentes. Também teríamos problemas se aumentássemos a
distância entre os planos, ou inclinássemos a câmera. Tudo teria de ser revolvido
novamente.
Enfim, para se utilizar o modelo Pinhole com a semelhança de triângulos, seria
necessário resolver vários outros problemas.
30
Ao invés disto, este trabalho adota uma solução de calibração por observação, a qual
baseia-se na observância da posição detectada pela câmera, para o alvo e para o
cabeçote, nos quatro cantos limites da mesa, quando um está sobre o outro, como
ilustrado na figura 18:
Figura 18 – Exemplo de calibração por observação
Fonte: Autor, 2014
A idéia é gerar uma função de transformação de coordenadas, onde uma leitura do
ponto verde no plano B, seja transformada em uma leitura do ponto verde no plano A.
Traçando uma reta do menor valor de X do ponto vermelho, até o maior valor de X do
ponto vermelho e realizando o mesmo para o ponto verde e igualando as duas
fórmulas, temos a partir dos dados de exemplo da Figura 18 uma fórmula de
conversão das coordenadas do alvo no plano B para coordenadas no plano A,
conforme mostrado na figura 19:
𝑥𝑉𝑑 − 52 𝑥𝑉𝑚 − 45
=
146 − 52
156 − 45
(3)
𝑥𝑉𝑚 = 1,18 × 𝑥𝑉𝑑 − 16,4
(4)
31
Figura 19 – Gerando uma fórmula de conversão de coordenadas
Fonte: Autor, 2014
Aplicando o mesmo para o eixo Y:
𝑦𝑉𝑑 − 19 𝑦𝑉𝑚 − 3
=
113 − 19
111 − 3
(5)
𝑦𝑉𝑚 = 1,15 × 𝑦𝑉𝑑 − 18,8
(6)
Utilizando as coordenadas transformadas do objeto verde, teríamos as duas
representações de coordenadas sobre o mesmo plano, ilustrado na figura 20:
Figura 20 – Coordenadas convertidas para o mesmo plano
Fonte: Autor, 2014
32
6.12 MINIATURIZANDO E EMBARCANDO TODA A SOLUÇÃO
A idéia de ter um computador trocando informações com o Arduino que por sua vez
controla os motores da mesa é funcional, porém é pouco prática. Ter que ligar o
computador, conectar a câmera e o Arduino, conectar a fonte de alimentação à mesa,
etc. parece trabalhoso e restritivo. É muito melhor pensar em um sistema embarcado,
onde o computador já está embutido na mesa e onde a fonte de alimentação pode ser
uma só.
O último passo do trabalho é considerar e implementar esta idéia e para isto substituir
o Arduino e o computador pessoal (PC) por um sistema miniaturizado.
A BeagleBone é um sistema de baixo custo, baseado no processador ARM Cortex A8,
com 256MB de memória RAM e muitos recursos de hardware, como entradas
analógicas (até 1.8V), I2C, SPI, Seriais e vários GPIOs disponíveis. Ela vem de fábrica
com o sistema operacional Linux instalado, rodando a distribuição Ångström. Outra
vantagem é que o sistema já vem com o OpenCV pré-instalado.
A versão disponível do OpenCV pré instalado no sistema da BeagleBone é mais atual
do que o que foi utilizado para gerar os algoritmos de detecção dos objetos. Portanto
foi necessário realizar um ajuste no software antes de transferir e compilar para a
placa.
Para o controle dos motores de passo, a BeagleBone tem um número de GPIOs maior
que o suficiente, porém não existe uma biblioteca bem difundida de controle destes
motores, como existe para o Arduino. Neste caso foi necessário escrever as rotinas e
os códigos para controlar os passos dos motores, a partir do zero. Os códigos gerados
podem ser encontrados nos anexos deste trabalho.
Para a realização do monitoramento da câmera e controle dos motores, o software foi
dividido em dois módulos, cada um realizando exatamente uma destas duas funções.
A comunicação entre estes dois módulos foi desenvolvida para ser realizada através
de um espaço de memória compartilhada no sistema operacional. Assim, quando o
software de detecção alterava a variável que continha informações da posição dos
objetos, o software de controle imediatamente tinha acesso à estas novas
coordenadas e podia tomar as providências para movimentar o cabeçote até o alvo.
Um diagrama do fluxo de informações do algoritmo de controle rodando na
BeagleBone pode ser visualizado na Figura 21.
O código para o controle dos motores de passo, utilizando a BeagleBone foi
disponibilizado para o público em forma de código fonte aberto e pode ser baixado
em:
https://github.com/zsantolim/beaglebone_stepper
33
Figura 21 – Diagrama do algoritmo
Fonte: Autor, 2014
A substituição da placa Arduino pela placa BeagleBone e a conexão de um dos
motores, foi ilustrada na figura 22:
Figura 22 – Diagrama de conexão de um dos motores à BeagleBone
Fonte: Autor, 2014
34
A figura 23 mostra a conexão da BeagleBone na mesa, já conectada aos circuitos de
atuação sobre os motores:
Figura 23 – BeagleBone conectada e controlando a mesa
Fonte: Autor, 2014
A fixação da câmera sobre a mesa pode ser visualizada na figura 24:
Figura 24 – Vista para a câmera
Fonte: Autor, 2014
35
7 RESULTADOS
Todos os passos do desenvolvimento foram muito bem sucedidos e tiveram
resultados positivos. Tanto o algoritmo de captura de informações através das
imagens da Webcam quanto o algoritmo de controle dos motores de passo
desempenharam suas devidas funções e como resultado, a mesa precisa somente
ser conectada à uma fonte de energia compatível (12V e 5V) para que em poucos
segundos o sistema termine de inicializar e comece a controlar a mesa.
A modularização dos algoritmos e o desenvolvimento de uma biblioteca de controle
própria para esta aplicação têm o benefício de ser altamente customizáveis. Por
exemplo, a biblioteca de controle dos motores de passo permite que facilmente
alteremos os motores e em seu lugar sejam instalados outros com características
distintas. A biblioteca é configurável para suportar diferentes tipos de motores de
passo, com ângulos de passo e tempo de controle diferentes.
Também é possível mudar as cores dos alvos, somente definindo uma nova faixa de
filtragem no início do código do OpenCV. Todo o resto do programa continua o
mesmo.
O cabeçote sendo controlado e movimentado até alcançar a posição sobre o alvo,
pode ser vista na figura 25:
Figura 25 – O cabeçote sendo posicionado automaticamente sobre o alvo
Fonte: Autor, 2014
36
8 CONCLUSÃO E TRABALHOS FUTUROS
O objetivo multidisciplinar desejado no início do projeto foi alcançado com sucesso.
Foram utilizadas muitas técnicas de processamento digital de imagens em conjunto
com visão computacional. Além disto houve uso intenso das linguagens C e C++
durante todo o desenvolvimento. Um algoritmo de controle simplificado: observação,
ação, medição do erro e correção foi desenvolvido. E ao final, toda a solução foi
embarcada em um sistema miniaturizado.
Apesar de concluído este trabalho permite diversas melhorias. Uma necessidade do
sistema é a realização de auto calibração todas as vezes em que é ligado. Para o
funcionamento e testes, as calibrações foram realizadas manualmente, porém, não é
difícil de vislumbrar um sistema que contenha calibração automatizada das posições
de borda (seção 6.11) dos objetos.
O sistema de controle simplificado, realizado sobre a observação da posição do alvo,
a posição do cabeçote e o erro entre estas duas distâncias, pode ser substituído por
outros paradigmas de controle, como por exemplo o PID ou Fuzzy, pois com o poder
de processamento disponível na BeagleBone, estes algoritmos não teriam problemas
em ser executados.
O sistema pode ser melhorado para a identificação de múltiplos objetos da mesma cor
e a escolha, dentre estes objetos, de qual seria o objeto alvo.
Se substituído o algoritmo de identificação dos objetos por cor, por outro método de
identificação, como por exemplo identificação por forma ou tamanho, teríamos um
equipamento capaz de classificar e separar vários objetos, podendo ser utilizado
facilmente em aplicações comerciais e industriais.
Na verdade, a união de todas as técnicas utilizadas neste trabalho, com algumas
modificações e customizações pode ser aplicada em diversas áreas, podendo
modernizar e aumentar a capacidade de várias aplicações existentes ou ser a base
para inúmeras novas aplicações.
37
REFERÊNCIAS
ALMONFREY, Douglas. Introdução à visão computacional. Vitória: Ifes, 2013.
BALLARD, Dana Harry. Computer vision. Nova Iorque: Prentice-Hall, 1982.
CABRE, T.P.; et al. Project-Based Learning Example: Controlling an Educational
Robotic Arm With Computer Vision. IEEE Revista Iberoamericana de Tecnologias
del Aprendizaje. IEEE. Vigo, v. 8, p. 135-142, agosto. 2013.
COLEY, Gerald. BeagleBone rev. A6 System Reference Manual.
BeagleBoard.org, 2012. Disponível em: <http://beagleboard.org/>. Acesso em 15.
Nov. 2013.
FLUSSER, Jan; ZITOVA, Barbara; SUK, Tomas. Moments and Moment Invariants
in Pattern Recognition. Chichester: Wiley, 2009.
GARIBOTTO, G.; et al. Computer vision control of an intelligent forklift truck. In: IEEE
CONFERENCE ON INTELLIGENT TRANSPORTATION SYSTEM. IEEE. 1997.
Boston. Anais... p. 589 – 594.
GUIMARÃES, Luciano. A Cor Como Informação. 3 ed. São Paulo: Annablume,
2004.
JEONGWOON Kim; SHIM, D.H. A vision-based target tracking control system of a
quadrotor by using a tablet computer. In: INTERNATIONAL CONFERENCE ON
UNMANNED AIRCRAFT SYSTEMS (ICUAS). IEEE. 2013. Atlanta. Anais... p. 1165 1172.
OPENCV DEV TEAM. OpenCV Documentation. 2013. Disponível em:
<http://docs.opencv.org>. Acesso em 7. Nov. 2013.
PAPANIKOLOPOULOS, N.P. Integrating computer vision and control for visionassisted robotic tasks. In: THE 1995 AMERICAN CONTROL CONFERENCE. IEEE.
1995. Seatle. Anais... v.1, p. 904 – 908.
SMITH, J.S.; YU, R. ; SARAFIS, I. ; LUCAS, J. Computer vision control of an
underwater manipulator. In: OCEANS ENGINEERING FOR TODAY'S
TECHNOLOGY AND TOMORROW'S PRESERVATION. IEEE. 1994. Brest. Anais...
v.1, I/187 – I/192.
STMICROELECTRONICS. L297 – Stepper Motor Controllers. Itália, 2001.
Disponível em <http://www.st.com>. Acesso em 7. Set. 2013.
STMICROELECTRONICS. L298 – Dual Full-Bridge Drivers. Itália, 2000. Disponível
em <http://www.st.com>. Acesso em 7. Set. 2013.
GONZALEZ, Rafael C.; WOODS, Richard E. Processamento Digital de Imagens.
ed. 3. São Paulo: Pearson Education - Br, 2011. 640p.
38
APÊNDICE A
CÓDIGOS FONTE PARA CONTROLE DOS MOTORES DE PASSO
Arquivo StepperMotor.h
#ifndef _STEPPERMOTOR_H_
#define _STEPPERMOTOR_H_
#include <stdio.h>
#include <stdlib.h>
#include "gpio.h"
#define
#define
#define
#define
STEPPER_STATE_A
STEPPER_STATE_B
STEPPER_STATE_C
STEPPER_STATE_D
0
1
2
3
typedef struct StepperMotor {
int
state;
// Motor sequence state
int gpioA1;
// GPIO number for positive side of the first winding
int gpioA2;
// GPIO number for negative side of the first winding
int gpioB1;
// GPIO number for positive side of the second winding
int gpioB2;
// GPIO number for negative side of the second winding
float stepSize; // The step size in degrees for this Stepper Motor
int speed;
// The desired RPM speed for the Stepper Motor
} StepperMotor_t;
void StepperMotor_setup(StepperMotor_t *motor);
void StepperMotor_stop(StepperMotor_t *motor);
void StepperMotor_step(StepperMotor_t *motor, int steps);
#endif
Arquivo StepperMotor.C
#include "StepperMotor.h"
void StepperMotor_setup(StepperMotor_t* motor) {
int port, pin;
// Initializes the ports and pins needed
// Pin gpioA1
port = (motor->gpioA1) / 32;
pin
= (motor->gpioA1) % 32;
setup_gpio_mem_map(port);
gpio_setup(port,pin,OUTPUT);
// Pin gpioA2
port = motor->gpioA2 / 32;
pin
= motor->gpioA2 % 32;
setup_gpio_mem_map(port);
gpio_setup(port,pin,OUTPUT);
// Pin gpioB1
port = motor->gpioB1 / 32;
pin
= motor->gpioB1 % 32;
setup_gpio_mem_map(port);
gpio_setup(port,pin,OUTPUT);
// Pin gpioB2
port = motor->gpioB2 / 32;
pin
= motor->gpioB2 % 32;
setup_gpio_mem_map(port);
gpio_setup(port,pin,OUTPUT);
39
// Initializes the state
motor->state = 0;
}
void StepperMotor_stop(StepperMotor_t *motor) {
gpio_write((motor->gpioA1)/32,(motor->gpioA1)%32,0);
gpio_write((motor->gpioA2)/32,(motor->gpioA2)%32,0);
gpio_write((motor->gpioB1)/32,(motor->gpioB1)%32,0);
gpio_write((motor->gpioB2)/32,(motor->gpioB2)%32,0);
}
void StepperMotor_step(StepperMotor_t* motor, int steps) {
float stepsPerRev, periodPerStep;
long int uPeriodPerStep;
int direction, stepsCount;
// Calculates the number of steps for one revolution
stepsPerRev = (360.0 / (motor->stepSize));
// Steps per revolution
periodPerStep = (60.0 / (stepsPerRev * motor->speed)); // Period per step, based on
the Steps Per Revolution and the Motor Speed
uPeriodPerStep = (long int) (periodPerStep * 1000000); // Period per step in
microseconds
if (steps > 0) {
direction = 1;
stepsCount = steps;
} else if (steps < 0) {
direction = 0;
stepsCount = -steps;
} else return;
while (stepsCount) {
switch (motor->state) {
case STEPPER_STATE_A:
gpio_write((motor->gpioA1)/32,(motor->gpioA1)%32,1);
gpio_write((motor->gpioA2)/32,(motor->gpioA2)%32,0);
gpio_write((motor->gpioB1)/32,(motor->gpioB1)%32,0);
gpio_write((motor->gpioB2)/32,(motor->gpioB2)%32,1);
break;
case STEPPER_STATE_B:
gpio_write((motor->gpioA1)/32,(motor->gpioA1)%32,0);
gpio_write((motor->gpioA2)/32,(motor->gpioA2)%32,1);
gpio_write((motor->gpioB1)/32,(motor->gpioB1)%32,0);
gpio_write((motor->gpioB2)/32,(motor->gpioB2)%32,1);
break;
case STEPPER_STATE_C:
gpio_write((motor->gpioA1)/32,(motor->gpioA1)%32,0);
gpio_write((motor->gpioA2)/32,(motor->gpioA2)%32,1);
gpio_write((motor->gpioB1)/32,(motor->gpioB1)%32,1);
gpio_write((motor->gpioB2)/32,(motor->gpioB2)%32,0);
break;
case STEPPER_STATE_D:
gpio_write((motor->gpioA1)/32,(motor->gpioA1)%32,1);
gpio_write((motor->gpioA2)/32,(motor->gpioA2)%32,0);
gpio_write((motor->gpioB1)/32,(motor->gpioB1)%32,1);
gpio_write((motor->gpioB2)/32,(motor->gpioB2)%32,0);
break;
default:
return;
break;
}
if (direction) {
motor->state++;
motor->state %= 4;
} else {
if (motor->state) motor->state--;
else motor->state = STEPPER_STATE_D;
40
}
stepsCount--;
usleep(uPeriodPerStep);
}
}
Arquivo main.c do Controlador dos Motores:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include
#include
#include
#include
<stdio.h>
<stdlib.h>
"StepperMotor.h"
"../../trab.h"
#define PROPORCAO_X 0.265
#define PROPORCAO_Y 0.03357
StepperMotor_t motorY;
StepperMotor_t motorX;
void main(int argc, char *argv[]) {
int shmId;
trackingInfo_t *tracking;
key_t key = SHARED_KEY;
float erroX, erroY, aux;
/*
* Cria o segmento compartilhado de memória
*/
if ((shmId = shmget(key,sizeof(trackingInfo_t), IPC_CREAT | 0666)) < 0) {
perror("Erro criando o segmento compartilhado de memoria: shmget");
exit(1);
}
/*
* Atrela o segmento compartilhado à nossa variável
*/
if ((tracking = (trackingInfo_t *) shmat(shmId, NULL, 0)) == (trackingInfo_t *) -1) {
perror("Erro atrelando o segmento de memoria aa variavel");
exit(1);
}
motorX.gpioA1 = 2*32 +
motorX.gpioA2 = 2*32 +
motorX.gpioB1 = 2*32 +
motorX.gpioB2 = 2*32 +
motorX.stepSize = 7.5;
motorX.speed = 120;
10;
11;
12;
13;
motorY.gpioA1 = 2*32 +
motorY.gpioA2 = 2*32 +
motorY.gpioB1 = 2*32 +
motorY.gpioB2 = 2*32 +
motorY.stepSize = 1.8;
motorY.speed = 120;
6;
7;
8;
9;
printf("Inicializando o motor...\n\r");
StepperMotor_setup(&motorX);
StepperMotor_setup(&motorY);
41
while(1) {
sleep(1);
erroY = ((1.149*tracking->targetY) - 18.831 - tracking->trackedY);
aux = erroY/PROPORCAO_Y;
if (erroY > 2 || erroY < -2)
StepperMotor_step(&motorY,(int)aux);
else StepperMotor_stop(&motorY);
erroX = ((1.180*tracking->targetX) - 16.40 - tracking->trackedX);
aux = erroX/PROPORCAO_X;
if (erroX > 2 || erroX < -2)
StepperMotor_step(&motorX,(int)aux);
else StepperMotor_stop(&motorX);
}
StepperMotor_stop(&motorX);
StepperMotor_stop(&motorY);
exit(0);
}
42
APÊNDICE B
CÓDIGOS FONTE PARA IDENTIFICAÇÃO DE OBJETOS PELA WEBCAM
Arquivo main.c do programa de captura e identificação de objetos pela webcam:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
<time.h>
<iostream>
<sys/types.h>
<sys/ipc.h>
<sys/shm.h>
<stdio.h>
<stdlib.h>
<fcntl.h>
<signal.h>
<fstream>
//bibliotecas OpenCV
#include "cv.h"
#include "highgui.h"
#include "ledcontrol.h"
#include "trab.h"
using namespace std;
//#define VIDEO_CAPTURE "Capture0.avi"
int lowerH=0;
int lowerS=0;
int lowerV=0;
int upperH=180;
int upperS=255;
int upperV=255;
int targetLowerH=69, targetUpperH=95;
int targetLowerS=85, targetUpperS=143;
int targetLowerV=0, targetUpperV=255;
int trackedLowerH=170, trackedUpperH=180;
int trackedLowerS=108, trackedUpperS=255;
int trackedLowerV=100, trackedUpperV=255;
int posX, posY, lastX, lastY;
int targetPosX, targetPosY, targetLastX, targetLastY;
int trackedPosX, trackedPosY, trackedLastX, trackedLastY;
IplImage* GetThresholdedImage(IplImage* imgHSV);
void findObject(IplImage* imgThresh);
//This function threshold the HSV image and create a binary image
IplImage* GetThresholdedImage(IplImage* imgHSV) {
IplImage* imgThresh=cvCreateImage(cvGetSize(imgHSV),IPL_DEPTH_8U, 1);
cvInRangeS(imgHSV, cvScalar(lowerH,lowerS,lowerV), cvScalar(upperH,upperS,upperV),
imgThresh);
IplConvKernel* erodeElement = cvCreateStructuringElementEx(3,3,0,0,CV_SHAPE_RECT);
IplConvKernel* dilateElement = cvCreateStructuringElementEx(8,8,3,3,CV_SHAPE_RECT);
cvErode(imgThresh,imgThresh,erodeElement);
cvDilate(imgThresh,imgThresh,dilateElement);
43
cvReleaseStructuringElement(&erodeElement);
cvReleaseStructuringElement(&dilateElement);
return imgThresh;
}
void findObject(IplImage* imgThresh) {
// Calcula os "raw moments" de 'imgThresh'
// Referência: http://en.wikipedia.org/wiki/Image_moment
CvMoments *moments = (CvMoments*)malloc(sizeof(CvMoments));
cvMoments(imgThresh, moments, 1);
double M10 = cvGetSpatialMoment(moments, 1, 0);
// Momento do eixo X
double M01 = cvGetSpatialMoment(moments, 0, 1);
// Momento do eixo Y
double Area = cvGetCentralMoment(moments, 0, 0); // Momento da área M00
lastX = posX;
lastY = posY;
// Captura a posição da centróide do objeto, baseado nos momentos da imagem
binarizada
posX = (M10/Area + lastX)/2;
posY = (M01/Area + lastY)/2;
// Se a área é pequena, não há objeto *** MUDAR
if(Area<50){
posX = lastX;
posY = lastY;
}
free(moments);
}
int main() {
CvCapture* capture=0;
char str[150];
int shmId;
trackingInfo_t *tracking;
key_t key = SHARED_KEY;
/*
* Cria o segmento compartilhado de memória
*/
if ((shmId = shmget(key,sizeof(trackingInfo_t), IPC_CREAT | 0666)) < 0) {
perror("Erro criando o segmento compartilhado de memoria: shmget");
exit(1);
}
/*
* Atrela o segmento compartilhado à nossa variável
*/
if ((tracking = (trackingInfo_t *) shmat(shmId, NULL, 0)) == (trackingInfo_t *) -1) {
perror("Erro atrelando o segmento de memoria aa variavel");
exit(1);
}
capture = cvCaptureFromCAM( 0 );
if(!capture){
printf("Capture failure\n");
return -1;
} else {
44
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 320);
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 240);
}
IplImage* frame = cvQueryFrame( capture );
//iterate through each frames of the video
while(true){
IplImage* frame = cvQueryFrame(capture);
if(!frame) {
break;
}
cvSetImageROI(frame,cvRect(62,22,200,160));
frame=cvCloneImage(frame);
IplImage* imgHSV = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3);
cvCvtColor(frame, imgHSV, CV_BGR2HSV); //Change the color format from BGR to HSV
// TRACKED
lowerH = trackedLowerH; upperH = trackedUpperH;
lowerS = trackedLowerS; upperS = trackedUpperS;
lowerV = trackedLowerV; upperS = trackedUpperV;
IplImage* imgThresh = GetThresholdedImage(imgHSV);
posX = trackedPosX; posY = trackedPosY; lastX = trackedLastX; lastY = trackedLastY;
findObject(imgThresh);
trackedPosX = posX; trackedPosY = posY; trackedLastX = lastX; trackedLastY = lastY;
// TARGET
lowerH = targetLowerH; upperH = targetUpperH;
lowerS = targetLowerS; upperS = targetUpperS;
lowerV = targetLowerV; upperS = targetUpperV;
IplImage* imgThreshTarget = GetThresholdedImage(imgHSV);
posX = targetPosX; posY = targetPosY; lastX = targetLastX; lastY = targetLastY;
findObject(imgThreshTarget);
targetPosX = posX; targetPosY = posY; targetLastX = lastX; targetLastY = lastY;
tracking->trackedX = trackedPosX;
tracking->trackedY = trackedPosY;
tracking->targetX = targetPosX;
tracking->targetY = targetPosY;
printf("Target: (%3d,%3d) Tracker:
(%3d,%3d)\n",targetPosX,targetPosY,trackedPosX,trackedPosY);
//Clean up used images
cvReleaseImage(&imgHSV);
cvReleaseImage(&imgThresh);
cvReleaseImage(&imgThreshTarget);
cvReleaseImage(&frame);
}
cvDestroyAllWindows();
cvReleaseCapture(&capture);
return 0;
}
Arquivo trab.h:
#ifndef _TRAB_H_
#define _TRAB_H_
#define SHARED_KEY 2468
45
typedef struct trackingInfo {
int
int
int
int
trackedX;
trackedY;
targetX;
targetY;
} trackingInfo_t;
#endif
Arquivo ledcontrol.h
#ifndef _LEDCONTROL_H_
#define _LEDCONTROL_H_
#include
#include
#include
#include
#include
#include
#include
#include
<stdio.h>
<stdlib.h>
<sys/types.h>
<sys/stat.h>
<unistd.h>
<assert.h>
<fcntl.h>
<sys/mman.h>
void ledControl(int led, int state);
#endif
Arquivo ledcontro.cpp
#include "ledcontrol.h"
void ledControl(int led, int state) {
FILE *f;
char buffer[128];
if ((led > 3) || (led < 0))
return;
snprintf(buffer, sizeof(buffer), "/sys/class/leds/beaglebone::usr%u/trigger", led);
if ((f = fopen(buffer, "w")) == NULL) {
perror("Cannot open led trigger file.");
//assert(0);
}
if (state)
fprintf(f, "default-on");
else
fprintf(f, "none");
fclose(f);
}
Download

controle dos movimentos de um sistema cartesiano para