terça-feira, 14 de julho de 2015

Robótica: PID Controller

O controle PID - ou controle proporcional integral derivativo - é uma técnica proveniente da engenharia e pode assumir um papel muito sutil e relevante na robótica. Em suma, seu objetivo é prover uma forma de manutenção de estados com retroalimentação, onde a partir de uma comparação entre o estado esperado na saída com o seu estado real (entrada), o controlador recebe os dados e atua de forma a fazer com que a saída seja alterada para o seu valor esperado, no melhor caso, ou o mais próximo possível, ou seja: realizar ciclos de manutenção de valor aproximado baseado em erro.

É composto por 3 coeficientes: ganho proporcional, ganho integral e ganho derivativo, coeficientes que serão empregados para a obtenção de valores mais satisfatórios. Cada coeficiente atuará em uma forma específica de correção:

  • P :: correção proporcional ao erro – a correção a ser aplicada ao processo deve crescer na proporção que cresce o erro entre o valor real e o desejado.
  • I  :: correção proporcional ao produto erro x tempo – erros pequenos mas que existem há muito tempo requerem correção mais intensa.
  • D :: correção proporcional à taxa de variação do erro – se o erro está variando muito rápido, esta taxa de variação deve ser reduzida para evitar oscilações.

A equação mais usual do PID é a apresentada no esquema a seguir:

Equação PID convencional

Onde KpKi Kd são os ganhos das parcelas P, I e D, e definem a intensidade de cada ação. Vale lembrar que esta equação pode variar dependendo do fabricante ou do caso a ser aplicado.

O gráfico a seguir representa um exemplo canônico da aplicação do controle PID:

Resultado de uma aplicação do CPID

Vale o projeto citado anteriormente como exemplo de aplicação: movimentação de um robô envolvendo sensores e motor. Esta técnica foi essencial na tarefa de fazer o robô andar seguindo linha, aprimorando o controle, suavidade e estabilidade no percurso, especialmente na realização das curvas.

Robótica: Line Follower Robot

Este foi um projeto acadêmico muito interessante em que participei, contemplando a robótica como ponto central, onde tínhamos que desempenhar no robô as tarefas de andar seguindo linha e desviando de objetos. Além destes problemas, havia a questão de sua parte elétrica e mecânica, envolvendo escolha de peças, bateria, fabricação do chassi, entre outros. Além disto, a necessidade de adaptar o robô para, por exemplo, subir rampas e andar por superfícies com anormalidades e interrupções na linha representavam outro nível de problema. Por fim, a forma de locomoção foi o ponto de partida para as decisões por vir, e foi dada preferência para um robô movido por esteiras.

Para desempenhar as tarefas do robô e sua interação com as outras partes, utilizamos os seguintes componentes:


  • Arduino Mega
Placa projetada com microcontrolador e suporte a entrada e saída, digital e analógica, para leitura e manipulação de dados e componentes. Utilizada para gerir e executar a lógica do robô em tempo real. É programada através da interface instalada no computador e trabalha com a linguagem Arduino, baseada em C/C++. Possui suporte a alimentação externa e interface USB, via que fornece comunicação com computador. Este modelo foi escolhido em alternativa ao Arduino Uno por ser maior, contendo suficientemente mais portas (digitais e analógicas) e mais memória.
Arduino Mega

  • Motor Shield
Utilizado juntamente com o Arduino para controlar a velocidade dos motores de corrente contínua. Possui canais de controle e um chip baseado em Ponte H, permitindo uma tensão ser aplicada em qualquer direção para ambos os motores. Suporta uma corrente de saída de 600mA e tensão de 4,5 a 36V.

MotorShield L298N


  • Sensores de Refletância
Sensores analógicos utilizados para detectar linha no percurso. Trabalham com led infravermelho e fototransistor, emitindo luz e detectando seu reflexo no solo, sendo possível assim medir intensidade do sinal captado e interpretá-lo como sendo ou não uma linha.
No projeto foram utilizados 5 sensores, sendo destes 3 sensores posicionados no centro, para ajuste de precisão do percurso reto, e 2 sensores subjacentes (esquerda e direita), para detecção de curva através das bordas na linha.
Modelo TCRT-5000

  • Sensores de Ultrassom
Sensores digitais utilizados para detectar objeto no percurso. São os "olhos" do robô (e parecem mesmo). Trabalham com onda sonora, que será emitida e rebatida pelo objeto mais próximo, retornando ao receptor. O cálculo de distância então irá derivar do tempo de emissão e recebimento do sinal.
No projeto foram utilizados 3 sensores, posicionados nos pontos central e laterais, de forma a trabalhar como uma visão periférica, primeiramente detectando um objeto a frente e posteriormente utilizando os laterais para contorná-lo, a uma distância predefinida. Uma alternativa seria utilizar apenas um deste sensor e direcioná-lo para as laterias utilizando um servo-motor convencional.
Modelo HC-SR04


Como utilizamos componentes que realizam algumas funções complexas, utilizamos algumas bibliotecas próprias, como a QTRSensors, do sensor de linha, e a NewPing, do sensor ultrassônico.

O robô se movimenta pelo acionamento de seus dois motores, comandados e controlados pelo Arduino e pela sua interação com o componente MotorShield, ao qual os motores são conectados. A direção é definida através da diferença da velocidade entre os dois motores. Para a realização de uma curva para a direita, por exemplo, o robô deve aumentar a velocidade do motor da esquerda e diminuir do motor da direita, simultaneamente, a fim de iniciar um movimento de rotação. Também, para girar em torno do próprio eixo, pode-se aplicar uma mesma velocidade aos dois motores, contanto que girem em sentidos opostos. A correção de velocidade dos motores, estratégia para realização de curvas e seguir linha, entre outros, são tarefas realizadas pelo controle PID, que será explicado mais detalhadamente em outro post.

O algoritmo no Arduino é constituído basicamente de 2 etapas: Setup e Loop. O Setup é a etapa de inicialização dos programas, setando as variáveis iniciais e realizando as ações primárias do robô, como por exemplo a calibragem dos sensores, que consiste numa varredura em 180º graus do robô, girando em torno do seu próprio eixo, para realizar a primeira detecção de linha e evoluir sua precisão, de acordo com fatores de ambiente. O Loop é onde definimos toda a ação em tempo real do robô, ou seja: validações, tratamentos e demais ações cíclicas que são realizadas no decorrer do percurso.

Para o desvio de objetos, a cada ciclo emitimos o sinal ultrassônico e lemos a distância até o objeto mais próximos, considerando um limite de distância. Nesta situação de proximidade, a decisão a ser tomada pelo robô primeiramente é parar e olhar os lados (através dos sensores ultrassônicos laterais), a fim de buscar o lado mais livre para percorrer, e tomar esta direção. Para realizar este desvio, o robô realiza um percurso predefinido em torno do objeto, andando primeiramente para o lado mais livre até se distanciar o suficiente do objeto, e assim, dobrar para o lado do objeto até cruzar sua posição e poder contorná-lo com mais uma curva, até que o robô ache a linha de volta.

No caso de haver interrupção na linha, o robô ativa um estado de sonda, anda uma certa distância para frente, procurando pela linha, e, caso não encontre, ele desfaz este caminho e o refaz, de forma sinuosa, até encontrar a linha nas proximidades do caminho.

Obs: fluxogramas, algoritmos, fotos do bicho e demais materiais não serão fornecidos por questões autorais.

quinta-feira, 9 de julho de 2015

Visão Computacional: Color Tracking, Line Detection & Shapes

Os programas que resultam nas imagens apresentadas abaixo foram desenvolvidos na linguagem C++, utilizando a IDE Eclipse Luna e o framework OpenCV, já citado anteriormente. Houveram várias tentativas de desenvolvimento em outras IDEs, tais como Visual Studio, NetBeans, Eclipse (Java) e DevC++ (que por fim é o menos recomendado), e também utilizando a linguagem Python. Porém, a que se sobressaiu e apresentou melhores resultados foi o C++ com Eclipse Luna, tanto pela estabilidade quanto pelo material de apoio que pode ser encontrado em fóruns e demais sites.

As bibliotecas mais usadas nos programas são a highgui e a imgproc. A highGUI é responsável por ações como a manipulação de janelas e seus componentes, sendo que estes podem interagir diretamente com o tratamento da imagem, pela leitura e gravação de arquivo em disco e em memória e pela leitura de frames da câmera. a imgProc é responsável pelo processamento de imagens, possuindo definições e funções que auxiliam o desenho em imagens e algumas formas de detecção por padrões.

Sobre os algoritmos desenvolvidos, existem trechos comuns à maioria dos programas de tratamento de imagens. Um deles é a conversão da imagem capturada de RGB para HSV (hue, saturation, value - ou - matriz, saturação e valor), pois este controle é mais eficiente e direto para se manipular o filtro (com iluminação e contraste, por exemplo) do que alterar valores RGB na matriz da imagem. Para se fazer a diferenciação das cores, por exemplo, o valor a ser alterado é relacionado à matriz, quando os demais servem para dar mais precisão na filtragem.

Esquema de sistema de cores HSV

Os algoritmos foram aplicados sobre a exibição da câmera do meu computador, em tempo real. Em todos os programas, o processamento foi mostrado em três janelas: uma com a imagem original da webcam, outra com o filtro aplicado (apenas tratamento, preto e branco, exibindo área ignorada e detectada respectivamente) e outra somando a imagem original com o desenho programado a partir da detecção (na detecção de cores, por exemplo, é apontado localização e nome da cor e, na detecção de formas, é desenhado a forma em torno do objeto).

Veja algumas imagens do resultado dos algoritmos:

Rastreamento de Cores

Detecção de Formas

Detecção de Linha

Neste projeto, alguns algoritmos foram utilizados no intuito de auxiliar atividades envolvendo robótica, através de monitoramento em tempo real, interpretação de informações e as possíveis interações com o robô. Uma adaptação interessante seria embarcar esta aplicação em um celular, por exemplo, possibilitando seu funcionamento portátil e uma transmissão online.

Nota: caso tenha interesse em estudar/utilizar os códigos-fonte, entre em contato por e-mail.

Programação: [C++] Templates, Friend Class & Operator Overloading

A linguagem C/C++ é indiscutivelmente a mais versátil de todas, dotada de recursos de baixo e alto nível e dinâmica para quaisquer tipos de programação. Além de ser a linguagem mãe de S.O.s como o Linux e o Windows, é possível trabalhar com orientação a objetos, listas, funções inline, assembly e mesmo reprogramar a própria linguagem (um dos tópicos que veremos a seguir...).

Trabalhando com classes em C++, podemos utilizar alguns recursos dinâmicos muito úteis como templates e operator overloading (sobrecarga de operadores).

Templates permitem-nos criar funções e classes genéricas. Pode ser usado, por exemplo, para definir containers que armazenam coleções de diferentes tipos de objetos. Veja o exemplo a seguir:
int max(int a, int b) { return a > b ? a : b; }
float max(float a, float b) { return a > b ? a : b; }
string max(string a, string b) { return a > b ? a : b; }
template <class X>X max (X a, X b) { return a > b ? a : b; }

main: 
    max(3, 7); 
    max("a", "b");
Este código permite utilizar uma única função para comparar diferentes tipos de variáveis ou objetos. Mas também podemos utilizar uma outra técnica, até mais sutil, para este tipo de problema...

A Sobrecarga de Operadores é uma técnica de programação utilizada para redefinir o significado dos operadores naturais da linguagem. Vamos supor que temos o objeto Item, e, declarados dois objetos, queremos comparar um com o outro em relação ao preço. Neste caso temos basicamente dois problemas: como saber que atributo comparar? Como fazer a comparação deste atributo naturalmente? Na sobrecarga de operadores, todos os operadores podem ser sobrescritos. Para este problema, faremos a sobrecarga do operador "<". Veja o código a seguir:
class Item {
public:
    Item(int i, float p) : id(i), preco(p) {};
    bool operator< (Item item) const{ return preco < item.preco; }
    int id;
    string nome;
    float preco;
};
int main() {
    Item i1(10,1);
    Item i2(20,2);
    (i1 < i2) ? cout << i1.id : cout << i2.id;
}
O programa então irá comparar o preço dos itens pelo preço e informará o respectivo id. Vamos apresentar agora algo ainda mais elaborado...Neste caso, se eu quisesse passar diretamente apenas o objeto Item para o operador cout, ele não saberia qual informação exibir. Para isto, podemos utilizar outra técnica de sobrescrita, que se trata na verdade da reescrita do operador "<<" interno da biblioteca ostream. Normalmente, a restrição de acesso a membros privados e protegidos da linguagem não nos permite fazer esta alteração, a menos que declaremos a classe ou membro como Friend. Veja o exemplo a seguir:
class Item {
public:
    Item(int i, string n, float p) : id(i), nome(n) , preco(p) {};
    bool operator< (Item item) const{ return preco < item.preco; }
    friend ostream& operator<<(ostream& out, Item& item)
        { out << item.nome; return out; }
    int id;
    string nome;
    float preco;
};
int main() {
    Item i1(10,"A",1);
    Item i2(20,"B",2);
    (i1 < i2) ? cout << i1 : cout << i2;
}
Com isto, ao invés de retornarmos o id  (definido manualmente), o programa automaticamente retornará o nome do item para sua saída padrão.

quarta-feira, 8 de julho de 2015

Visão Computacional: Concepts & OpenCV

Podemos descrever a visão computacional como "a ciência e tecnologia das máquinas que enxergam". A partir da captura de imagens - ou vídeo - é possível extrair infinitas possibilidades de informações. Esta técnica é largamente utilizada no meio industrial, em sistemas artificiais, biotecnologia, modelagem de ambientes, organização de informação, interação (atrelado a interação humano-computador) dentre outras. Ela atua especialmente em tarefas como reconhecimento, detecção, identificação, tratamento de dados e de imagem em si.

Seu fluxo funcional se baseia na seguinte sequência de tarefas: aquisição de imagem, pré-processamento, extração de características, detecção e segmentação, e por fim, processamento de alto nível. A partir destes - ou parte destes - temos uma gama de aplicações, tais como computação gráfica, processamento de imagens, aprendizagem de máquina, reconhecimento de padrões, sistemas de visão entre outros, além de ser uma forte aliada à robótica.

O OpenCV é um framework open-source multiplataforma para desenvolvimento de aplicativos na área de visão computacional. Foi originalmente desenvolvido pela Intel em 2000 e é bastante utilizado no meio acadêmico e também comercial. Sua biblioteca possui módulos de processamento de imagens e vídeo I/O, estrutura de dados, álgebra linear, interface gráfica (GUI), sistema de janelas independentes, controle de mouse e teclado, além de mais de 350 algoritmos de visão computacional como: filtros de imagem, calibração de câmera, reconhecimento de objetos, análise estrutural entre outros, podendo inclusive trabalhar com estas funções paralelamente e com processamento em tempo real.

O framework foi originalmente desenvolvido em C/C++, mas atualmente é suportado nas linguagens Java, Python e Visual Basic, sendo possível desenvolver para diversas plataformas, inclusive Android e iOS. Algumas de suas aplicações englobam interface humano-computador, identificação de objetos, sistema de reconhecimento facial e de movimentos, robôs móveis, reconstrução 3D entre outros.

Alguns exemplos de utilização da visão computacional atualmente:

Reconhecimento facial

 
 
Jogos e simulação virtual

Monitoramento urbano

Tratamento de imagens

A visão computacional contribui com a tecnologia e a sociedade à medida que evolui e se especializa. Hoje ela tanto auxilia e diverte seus usuários quanto pode salvar vidas. Por exemplo, em um evento esportivo, com milhares de espectadores, a visão computacional pode ajudar a monitorar a multidão, de forma a evitar que um tumulto qualquer faça as pessoas ficarem bloqueadas, com ferimentos ou até mesmo vítimas fatais. Não há limites para a aplicação da visão computacional.

Novas idéias surgem a cada dia e assim novos desafios dão abertura a inovações e descobertas, estimulando a evolução da visão computacional e difundindo seu uso em todas as áreas possíveis.

Música: Blues Rock

Se você começou a ler por aqui, eis uma trilha sonora para acompanhar o restante das leituras.

Há aproximadamente 2 anos fui chamado a contribuir em uma rede de sites de rádio. Desta rede, 3 rádios possuem um canal de Blues Rock que dirijo: RadioTunes, JazzRadio e RockRadio, tendo a JazzRadio ganhado prêmio como melhor rádio da internet em 2014, pela JazzWeek.

Este canal contempla o blues das vertentes mais voltadas ao rock e à melodia, com muitos solos, algumas baladas, honky tonks, muitos clássicos, algumas novidades e - muito recorrentemente no mundo da música - várias versões de clássicos, como Bo Diddley, Freddie King, Howlin' Wolf entre outros (incluindo eles mesmo). Alguns representantes dos variados gêneros: ZZ Top, Johnny Winter, Rory Gallagher, Jimmy Dawkins, Tommy Castro, Gary Moore, Rick Derringer, Stevie Ray Vaughan, Eric Clapton, Alvin Lee, Joe Bonamassa, etc.

O site possui também a versão mobile e assinatura Premium, para reprodução de qualidade excelente das músicas e sem comerciais.

Deleite-se ao som do Blues!

Nota: As músicas são negocialmente autorizadas pelas gravadoras, pagando-se royalties pelo stream.

terça-feira, 7 de julho de 2015

Início

Estou iniciando este blog - temporário - como forma de memória e publicação de informações relevantes de minha atuação na área de TI (códigos, trabalhos, dicas entre outros) e falando um pouco também sobre minha paixão, a música.