quarta-feira, 29 de fevereiro de 2012

Impressões sobre a Câmera IP Feasso F-IPCam01

Ha uma semana finalmente comprei uma câmera IP wireless, coisa que eu estava querendo a muito tempo.  É um lançamento recente da marca Feasso, modelo F-IPCAM01, brinquedinho bem legal, ela tem pan-tilt, consegue girar 270 graus na horizontal, quase 90 na vertical e vem com um programa de controle que pra falar a verdade nem tive a curiosidade de instalar pra ver como é.

E aí tive boas e más surpresas. Minha intenção era tentar instalar a câmera no meu robozinho e tentar algo com navegação por imagens, mas assim que vi a fonte dela já percebi que não ia dar. A fonte fornece 2 amperes pra câmera, alimentar isso com baterias é complicado, a não ser que eu faça outro robô bem mais parrudo que o atual. Com o que eu tenho não tem jeito mesmo.

A outra decepção, mas que eu já meio que esperava, é que em lugar nenhum, nem no manual, nem no CD ou no site tem qualquer referência aos comandos que a câmera aceita, cheguei até a mandar um email pro representante da Feasso no Brasil, e adivinha... nenhuma resposta. As vezes eu acho que alguns fabricantes de hardware têm titica de galinha na cabeça, fazem um equipamento cheio dos recursos e não dizem como usar esses recursos em aplicações, será que não passa pela cabeça deles que se os programadores conseguirem desenvolver aplicações para o equipamento deles isso incentivaria a venda desses produtos? Ou eles têm tão pouca imaginação que pensam que o programa que vem junto com a câmera atende todas as aplicações possíveis para o equipamento?

Mas felizmente a câmera tem dentro dela algumas páginas web que permitem controlar boa parte dos recursos e com a ajuda do Google Chrome não foi difícil interceptar toda a comunicação entre a página e a câmera, no fim acabei descobrindo quase todos os comandos da câmera. Que felicidade... Imediatamente fiz uma aplicaçãozinha em delphi pra testar o controle da câmera e consegui que ela fizesse todo tipo de movimento.

E aí a outra decepção, pra isso ser útil em um robô, não adianta apenas poder mover a câmera, é preciso poder também quantificar esse movimento e isso a câmera não faz. Não tem como você dizer pra ela girar tantos graus e a câmera também não diz quantos graus ela girou. Na verdade, não tem nenhuma precisão nos movimentos dela, mas afinal de contas é uma câmera de segurança, não foi feita pra robôs.

Ela tem três tipos básicos de movimento: patrulha, linear e por passo, e cada um desses tipos tem opções em todas as direções. Na patrulha ela fica repetindo o mesmo movimento esquerda-direita, pra cima pra baixo sem parar. No movimento linear, você manda ela ir pra alguma direção e ela vai, até chegar no fim de curso e para. No movimento por passo, ela vai pra alguma direção em passos, cada comando faz ela mover um pouco naquela direção. Até que seria útil se os passos fossem sempre iguais movendo sempre o mesmo angulo, mas não é assim, é uma coisa meio aleatória quantos graus cada passo gira a câmera.

Mas também tive boas surpresas com a câmera. Ela tem uma saída de 5 volts que serve pra ativar algum alarme caso a câmera detecte movimento e é possível enviar comandos pra ativar ou desativar essa saída. É claro que não tenho nenhuma intenção de usar alarmes com a câmera, mas uma saída de 5 volts que pode ser ligada e desligada via programa é extremamente útil e me animou a implementar uma idéia que eu já tinha a algum tempo: de instalar um laser na câmera pra medir distâncias. E olha só... Funcionou... e com um laser comprado em camelô por 6 reais... No próximo post falo sobre esse projeto. Abaixo uma foto de como ficou.


sexta-feira, 24 de fevereiro de 2012

Download do tutorial de robô usando sucata

Acabo de colocar a versão PDF do tutorial para download no meu SkyDrive, então quem estiver interessado pode baixar ou visualizar o tutorial completo clicando aqui. É um projeto aberto. Sugestões, críticas e principalmente colaborações para incrementar o tutorial serão bem vindas. Pretendo fazer revisão periódicas do tutorial acrescentando mais informações, circuitos, técnicas, etc. Mas sempre dentro da proposta de usar de preferência material extraído de sucata e/ou de baixo custo e indicar técnicas caseiras e baratas para resolver problemas comuns no estudo da robótica. 

sábado, 18 de fevereiro de 2012

PIC ou Arduíno?

Desde que iniciei o projeto do robozinho controlado por porta paralela, já venho imaginando que a próxima versão vai usar um microcontrolador. E de lá pra cá estou tentando resolver em qual microcontrolador vale a pena investir. Percebi que a disputa hoje está entre PIC e Arduíno, não tenho visto muita gente falando do 8051, então imagino que atualmente ele não faça muito sucesso entre os entusiastas da robótica. Deve ter alguma boa razão pra isso. Vi muitos sites comparando o PIC com o ATmega usado no Arduíno, mas senti que dificilmente vou conseguir uma opinião isenta, os dois lados têm defensores ardorosos e com argumentos bem convincentes.

Sem dúvida o PIC 18F2550 e seu irmão mais cheio de pernas o 18F4550, são mais rápidos  e tem mais memória do que o ATmega168 e o ATmega368 que são os mais comuns nas placas Arduíno. Mas o Arduíno com certeza tem mais documentação disponível e acessível para os pobres mortais que querem iniciar na programação de microcontroladores. Também pesa o fato de ter compiladores freeware de melhor qualidade (penso eu) e uma grande biblioteca de funções disponível para programação, visto que é uma plataforma aberta.

Mas ser uma plataforma aberta não significa que é barato desenvolver dispositivos com o ATmega. A placa do padrão Arduíno realmente facilita muito o desenvolvimento de protótipos, mas parece que para por aí. Tem centenas de shields no mercado para encaixar no Arduíno e geralmente a documentação se limita a dizer qual pino encaixa aonde, mas e daí? Da maneira que eu vejo, isso serve pra testar o circuito, ver se tudo vai dar certo e se for o caso fazer as correções necessárias. Mas finalizados os testes, quero poder montar o dispositivo final da maneira mais compacta e econômica possível. Não quero gastar uma placa Arduíno e vários shields para cada dispositivo que eu for montar, isso não faz muito sentido. Afinal uma placa padrão Arduíno custa entre R$ 120,00 e R$ 250,00 conforme o tipo e os shields, bom, tem de todos os preços, mas nunca são baratos. Um microcontrolador, que no final é o que importa, não chega a R$ 20,00 e os sensores usados nos shields também são muito mais em conta quando comprados separadamente fora dos shields. Nas minhas navegações não tenho visto muitos circuitos usando o ATmega fora da placa Arduíno. Já para o PIC, uma rápida prece ao Santo Google retorna dúzias de circuitos usando o microcontrolador e sensores variados sem placas pré-montadas (e caras).

Então até o momento, estou inclinado a investir no PIC.

sexta-feira, 17 de fevereiro de 2012

Apêndice - Duplicando polias e engrenagens

Quem se envolve com robótica, cedo ou tarde acaba precisando usar polias e engrenagens. E aí descobre que é extremamente difícil encontrar em sucatas de impressoras e outros equipamentos eletrônicos, polias e engrenagens nas medidas e quantidades necessárias para o projeto em execução. Um robô que se movimenta usando rodas ou esteiras e usa sistema de direção diferencial, precisa que  todo o sistema de movimento seja duplicado. Vai ser necessário conseguir dois motores iguais e dois conjuntos de engrenagens/polias iguais para que o movimento possa ser controlado adequadamente. Uma situação comum é encontrar uma engrenagem/polia que seria perfeita para o projeto se fosse possível conseguir outra igual, mas isso nem sempre é possível e nesse caso, a solução é duplicá-la. Outra situação comum é encontrar uma engrenagem com o diâmetro e tamanho de dentes corretos, mas com o furo do meio na medida errada para o projeto.

A boa notícia é que é possível duplicar uma engrenagem com materiais de baixo custo e sem envolver equipamentos caros. Em resumo, a duplicação de uma engrenagem envolve fazer um molde com a engrenagem disponível e depois preencher o molde com resina. Eventualmente pode ser necessário modificar o tamanho do furo central. Nesta seção abordaremos as técnicas para duplicar engrenagens e polias.

O silicone líquido

Em primeiro lugar é preciso conseguir um material para fazer o molde. Para isso a melhor opção é o silicone líquido. Este tipo de silicone é vendido com um endurecedor que deve ser misturado ao silicone nas proporções indicadas. Depois de algum tempo o silicone endurece e se transforma em uma borracha flexível. O silicone pode ser encontrado em casas que vendem materiais para artesanato e/ou pintura artística, também não é difícil de encontrar para venda on-line pela internet. Neste caso, faça buscas por “borracha de silicone” ou “silicone líquido”. A cor do silicone indica a sua dureza (ou flexibilidade) depois de curado. Os mais indicados para moldar engrenagens são o branco e o azul. Existem também silicones capazes de suportar alguns metais derretidos (silicone vermelho ou marrom), mas são bem mais caros. O silicone azul utilizado neste projeto pode ser encontrado por um preço que varia de R$ 22,00 a R$ 30,00 o litro (preços de 2011). Um litro é suficiente para fazer vários moldes, considerando que cada molde usa cerca de 100 ml de silicone. A figura 34 mostra o silicone utilizado neste projeto.



Figura 34: Silicone líquido azul e endurecedor

O molde

Para fazer o molde, consiga um recipiente de plástico não muito fino. Um plástico muito fino pode deformar e atrapalhar a modelagem. Também é importante que tenha o fundo plano. Recipientes de plástico com tamanhos e espessuras variadas podem ser encontrados facilmente em lojas de materiais para festas.

Para conseguir engrenagens de boa qualidade, também vai ser necessário dispor de uma superfície bem nivelada. Uma boa dica é fazer uma mesa niveladora. É bem simples e evita vários problemas depois. Pode ser feita com um pedaço de madeira lisa e quatro parafusos com suas respectivas porcas. Faça furos nos cantos da madeira no diâmetro dos parafusos e fixe as porcas alinhadas com os furos. Assim os parafusos podem ser rosqueados para cima e para baixo até que a madeira fique bem nivelada. A figura 35 mostra a mesa niveladora feita para este projeto. 

Figura 35: Mesa niveladora

Use uma fita adesiva dupla face para fixar a engrenagem no fundo do recipiente plástico (figura 36). Fitas bem finas dão um resultado melhor, existe uma fita dupla face de borracha que é usada para fixar quadros na parede, essa não é indicada porque é muito grossa e cria sulcos no molde que acabam atrapalhando a modelagem. O outro tipo de fita é uma fita adesiva comum com adesivo dos dois lados, pode ser facilmente encontrada em papelarias e é bem mais barata.  

Figura 36: Recipiente para o molde com a engrenagem fixada no fundo
Antes de preparar a mistura do silicone determine a quantidade necessária para fazer um molde com aproximadamente 1,5 cm de espessura, para isso apenas despeje água no recipiente até ter 1,5 cm de água no fundo e depois verifique quantos ml de água foram utilizados. Para o recipiente que foi usado neste projeto, 100 ml foi a medida ideal. Na mesma loja onde foi comprado o recipiente para o molde, também foi possível encontrar copinhos descartáveis de 100 ml e palitos de sorvete para misturar o silicone.

Dica: Se o silicone ficou algum tempo armazenado, o que com certeza é o caso quando você acaba de comprar um pote, ele tende a se depositar no fundo do pote. Antes de usar, é uma boa idéia misturar misturar bem o silicone com um pedaço de madeira para deixa-lo mais homogêneo, inclusive raspando bem o fundo do pote, você vai perceber que o silicone no fundo do pote é muito mais denso que o que está na superfície.
Depois de fixar a engrenagem no fundo do recipiente, coloque-o em uma superfície nivelada ou na mesa niveladora e faça a mistura do silicone com o endurecedor. Para o silicone usado neste projeto, a medida que deu melhores resultados foi duas tampinhas de endurecedor para 100 ml de silicone. É preciso cuidado para não produzir muitas bolhas no silicone enquanto estiver misturando, fazendo movimentos lentos e suaves. Também é importante misturar bem o silicone com o endurecedor, raspando as laterais e o fundo do copinho para misturar o silicone que fica aderido às paredes do recipiente. Depois de misturado, algumas pancadinhas no fundo do copinho ajudam a fazer subir as bolhas que estiverem no silicone. Essa operação não deve demorar mais do que dois minutos, depois de misturado com o endurecedor, o silicone começa a endurecer rápido e é importante que ele seja despejado no molde enquanto ainda está bem líquido para que forme uma superfície nivelada na parte de cima. 

Dica: Depois de despejar o silicone no copinho medida e antes de misturar o endurecedor (perceberam que eu negritei, inclinei e sublinhei a palavra antes né?), deixar o copinho descansar por alguns minutos vai fazer com que boa parte das bolhas que estiverem la dentro subam e estourem na superfície.

Despeje o silicone no recipiente de plástico e espere cerca de 3 horas para retirar o molde do recipiente e a engrenagem do molde (Figura 37). A cura completa só acontece depois de 24 horas. É aconselhável esperar a cura completa antes de usar a resina no molde ou ela pode aderir ao silicone, outra opção é usar algum desmoldante. Um desmoldante é uma substancia, geralmente em spray, que é colocada no molde para que a resina não grude nele. Existe um óleo de silicone em spray que é próprio para isso e é facilmente encontrado em lojas de ferramentas.

Importante: Não use recipientes de vidro para fazer o molde. O silicone adere ao vidro. 

Figura 37: Silicone no recipiente esperando a secagem

Depois de seco, o silicone forma uma borda ligeiramente levantada devido à tensão superficial que existe enquanto está líquido. Essa borda deve ser retirada para garantir que o molde fique bem nivelado quando for colocada a resina. Com uma tesoura, corte as bordas conforme mostrado na figura 38. 

Figura 38: Bordas sendo cortadas para garantir bom nivelamento do molde
Figura 39: O molde depois de pronto

A resina

Durante o desenvolvimento deste projeto foram testados vários tipos de resina. A mais fácil de conseguir é a resina de poliéster pré-acelerada. Essa resina é utilizada para fazer peças de fibra de vidro, então pode ser encontrada em qualquer loja de tintas e é bem barata. Mas infelizmente não serve para fazer engrenagens. Depois que seca apresenta uma retração bem significativa o que acaba alterando o diâmetro da peça. Além disso, a resistência mecânica dela é baixa, uma engrenagem feita com essa resina nem pôde ser testada porque caiu no chão e quebrou.

Também foi feito um teste com acrílico em pó auto-polimerizante, material utilizado pelos dentistas para fazer próteses. Este material é um pouco mais caro e mais difícil de encontrar já que só é encontrado em casas especializadas em materiais para dentistas. Tem uma excelente resistência mecânica e não tem o problema da retração como a resina de poliéster. O problema do acrílico em pó é que depois misturado com o líquido ele se transforma em uma pasta bastante densa e é difícil colocar a pasta no molde de borracha, preenchendo todos os detalhes sem deformar o molde que é bem flexível. Também é possível colocar diretamente o pó no molde e depois gotejar o líquido sobre ele. O problema dessa técnica é garantir que o líquido se espalhe por todo o pó de maneira homogênea. Se uma parte do pó não receber o líquido, não vai endurecer e a engrenagem será inutilizada.

Os melhores resultados foram obtidos com a resina epóxi. Não é uma resina cara (por volta de R$ 40,00 o litro – valores de 2011), tem uma ótima resistência mecânica, não apresenta retração depois de seca e a mistura da resina com o endurecedor forma um líquido com uma viscosidade satisfatória para ser despejado no molde preenchendo todos os detalhes. O único problema é que é difícil encontrar estabelecimentos que vendam essa resina. Como não foi encontrada nos estabelecimentos da cidade, a opção foi comprar pela internet. Existem vários tipos de resina epóxi, o ideal é que seja um tipo com baixa viscosidade.

É preciso muito cuidado ao manipular a resina epóxi. Use jornais velhos para evitar que respingos possam atingir a superfície de trabalho e palitos de sorvete e copinhos descartáveis para fazer a mistura, esta resina depois de seca é extremamente dura e os respingos não saem facilmente.

Uma superfície nivelada também é importante no momento de preencher o molde com a resina, então antes de fazer a mistura coloque o molde na mesa niveladora. A resina epóxi é razoavelmente lenta para secar, demora pelo menos 5 horas para que possa ser retirada do molde, mas só atinge o máximo da sua resistência mecânica depois de 24 horas.

Câmara de secagem

A temperatura e umidade do ar influenciam bastante no processo de cura da resina. O ideal é um ambiente seco e ligeiramente aquecido, isso acelera a secagem e melhora a resistência da engrenagem. Não é difícil fazer uma câmara de secagem para a resina, é basicamente uma caixa de madeira com uma lâmpada incandescente de 40W dentro dela. Na falta de uma caixa de madeira apropriada, uma câmara de secagem usando uma prateleira de armário foi improvisada para este projeto, conforme mostrado na Figura 40.

Resista à tentação de colocar o dedo na resina para verificar se está seca, antes de secar a resina fica em um estado gelatinoso e a pressão do dedo pode deformar a engrenagem. Use as sobras da mistura para deixar uma porção à parte como controle.  

Figura 40: Câmara de secagem improvisada em um armário

O furo central

Se for possível encontrar uma engrenagem que tenha o diâmetro, o tamanho e numero de dentes correto para seu projeto e, além disso, tenha também o furo central na medida correta para o eixo onde a engrenagem será fixada, parabéns, considere-se com sorte. Mas eventualmente acontece de a engrenagem não ter um furo central na medida correta. Se for um furo pequeno e você precisa de um furo maior, talvez seja possível aumentar o furo com uma broca apropriada. Mas se o furo não for tão pequeno assim e você precisar aumentar o tamanho dele, vai acabar descobrindo que é muito difícil aumentar seu diâmetro mantendo o furo exatamente centralizado na engrenagem. E uma engrenagem com o furo fora de centro, mesmo que ligeiramente, fica inutilizada. Uma situação parecida ocorre quando a engrenagem tem um furo maior do que o necessário, nesse caso não há como diminuir o diâmetro dele. A solução, tanto para um caso quanto para o outro, é eliminar o furo e fazer outro.

Para eliminar o furo é bastante simples, basta cortar o pino central do molde e moldar a engrenagem sem o furo, como mostrado na Figura 41. Já para fazer o novo furo é bastante mais complicado, especialmente porque o furo precisa estar muito bem centralizado na engrenagem.  

Figura 41: (a) Molde com o pino central retirado (b) A engrenagem depois de pronta

Esquadro de centrar

O problema de fazer o novo furo é como determinar a posição exata do centro da engrenagem. Existe um tipo de esquadro que é próprio para marcar o centro de uma peça circular, o esquadro de centrar, mas é muito difícil de ser encontrado e costuma ter um preço proibitivo. Felizmente, não é difícil fazer um esquadro de centrar caseiro com um custo muito baixo.

Só é necessário dispor de um esquadro de desenho triangular comum, do tipo com ângulos de 45º e 90º. O primeiro passo é cortar o lado do esquadro que tem os ângulos de 45º (hipotenusa). Em seguida a parte cortada deve ser posicionada e colada de modo que um dos ângulos de 45º divida o ângulo de 90º na metade, conforme mostrado na figura 42.  

Figura 42: (a) Esquadro de desenho cortado (b) Depois de posicionado e colado
Para marcar o centro da engrenagem, posicione-a de modo que suas bordas encostem no ângulo reto interno do esquadro (figura 43) e risque com uma caneta, lápis ou a ponta seca de um compasso, conforme o material da engrenagem. Faça pelo menos três ou quatro riscos. A intersecção entre os riscos marca o centro da engrenagem. Depois quando for furar, fure primeiro com uma broca fina e depois com a broca da medida desejada para o furo.  

Figura 43: (a) Engrenagem posicionada no esquadro (b) Depois de riscada

Links úteis


Aqui alguns links muito bons pra quem quiser se aprofundar mais:

Resina

1) Um breve mas bem completo resumo sobre tipos de resina e suas aplicações e características. Também tem um FAQ com informações bem importantes pra quem quiser fazer peças mais bem acabadas:

http://www.fazfacil.com.br/reforma-construcao/resinas-poliester-epoxi/

Silicone

1) Informações acessíveis e úteis sobre tipos de silicone e suas aplicações:

http://www.fazfacil.com.br/materiais/silicone.html



Índice

2) Visão geral do projeto
3) Fonte de alimentação para testes de bancada
4) A porta paralela
5) Motores de passo
6) Montagem dos circuitos
7) Montagem do robô
8) Alimentação
9) Software de navegação
10) Conclusão
Apêndice - Duplicando polias e engrenagens


    10) Conclusão


    Este trabalho mostra que é possível construir dispositivos robóticos com materiais extraídos de sucata e/ou de baixo custo. Apesar do dispositivo descrito aqui ser bastante simples, nada impede de usar os mesmo conceitos e materiais para criar dispositivos mais sofisticados. O pequeno robô desenvolvido tem os elementos básicos para o estudo da robótica. Envolveu programação, comunicação do computador com um dispositivo externo, eletrônica e a montagem física do hardware.

    O foco no estudo dos motores de passo tem a intenção de divulgar e desmistificar o uso destes motores, provendo o conhecimento básico para que sejam utilizados em outros projetos. É um recurso importantíssimo para o desenvolvimento de dispositivos robóticos e são muito facilmente obtidos em impressoras sucateadas.

    É fato que o robô descrito neste trabalho nada faz além de se mover, mas espera-se que seja considerado pelos estudantes como um ponto de partida para projetos mais elaborados. Por exemplo, poderiam ser instalados sensores que retornem sinais para o computador, a comunicação com o computador poderia ser feita por alguma tecnologia sem fio e utilizando outras portas como a porta COM ou a porta USB, o programa poderia ser melhorado para permitir o armazenamento de rotas pré-programadas, entre muitos outros aprimoramentos que podem ser implementados a partir deste projeto.

    E finalmente gostaria de deixar registrado que é extremamente recompensador ver o resultado de um trabalho ganhar vida e se mover fisicamente pelo mundo real. Ao ver o pequeno robô ganhando a capacidade de movimento é difícil não ter o impulso de fornecer a ele mais habilidades e recursos através de dispositivos, sensores e de uma programação mais elaborada. Às vezes tenho a impressão que encontrar utilidades práticas e acadêmicas para robôs é só um pretexto, e que no fundo o que os pesquisadores e desenvolvedores realmente querem é ver suas criações evoluindo, crescendo e se tornando cada vez mais independentes.
     

    9) Software de navegação


    Tão importante quanto os circuitos e a montagem, é o software que irá controlar os movimentos do robô. A unit ParBib descrita no capítulo 4, foi criada apenas para enviar sinais à porta paralela, mas para que esses sinais se transformem em movimento no robô, eles precisam ser gerados com coerência e sincronia, sendo essa a função do software de navegação.

    Para gerar os sinais de navegação foi desenvolvida uma classe que fornece os recursos básicos de movimentação do robô. A classe TRobotMove declarada dentro da unit RobotMove, permite selecionar entre 9 tipos de movimento, alterar a velocidade e ligar/desligar o modo de alto torque.

    Métodos públicos da classe TRobotMove

    Abaixo segue a declaração da parte pública da classe e uma breve explicação sobre o uso de cada método. O tópico seguinte contém a listagem completa da classe.

    type
      TRobotMove = class
      public
        constructor Create(AOwner: TComponent; LPTPort: TLPT;
                           BaseTm: cardinal);
        destructor Destroy; override;
        procedure Ahead;
        procedure Back;
        procedure Stop;
        procedure Right;
        procedure Left;
        procedure VeryRight;
        procedure VeryLeft;
        procedure SpinRight;
        procedure SpinLeft;
        property PulseTime: cardinal;
        property HiTorq: boolean;
      end;


    constructor Create(AOwner: TComponent; LPTPort: TLPT;
                       BaseTm: cardinal);
    Construtor da classe. Usa os seguintes parâmetros:

    AOwner: Pode ser qualquer componente descendente de TComponent. Normalmente é o próprio form principal da aplicação. Este parâmetro é necessário porque a classe usa internamente um timer para gerar os pulsos e a construção do timer exige um Owner.

    LPTPort: Porta paralela que será usada. Em geral é a LPT1.

    BaseTM: Tempo base para o timer em milissegundos. Esse é o tempo que será usado entre cada pulso enviado para os motores. Quanto menor o tempo, mais rápido o robô vai se mover. Existe um valor mínimo para esse tempo que depende do tipo do motor de passo e do peso do robô. Caso sejam usados valores abaixo do mínimo, os motores começam a perder passo ou podem nem se mover.


    destructor Destroy;
    Destrutor da classe.

    procedure Ahead;
    Move para frente em linha reta.

    procedure Back;
    Move para trás em linha reta.

    procedure Stop;
    Para o movimento, mas as bobinas continuam ativadas. Isso cria um efeito de “freio de mão” no robô.

    procedure Right;
    Curva leve à direita. A roda da direita passa a rodar com a metade da velocidade da roda da esquerda.

    procedure Left;
    Curva leve à esquerda. Aqui é a roda da esquerda que tem sua velocidade reduzida pela metade.

    procedure VeryRight;
    Curva fechada à direita. A roda da direita fica travada na mesma posição e a roda da esquerda continua no movimento normal. O efeito disso é que o robô começa a circular em torno da roda da direita.

    procedure VeryLeft;
    Curva fechada à esquerda. Idem acima.

    procedure SpinRight;
    Giro à direita. A roda da direita tem o movimento invertido e passa a rodar para trás, enquanto a roda da esquerda se move para frente. O efeito é que o robô começa a girar no sentido horário sem sair do lugar.

    procedure SpinLeft;
    Giro à esquerda. A roda da esquerda inverte o movimento e o robô gira no sentido anti-horário.

    property PulseTime: cardinal;
    Permite ler e alterar o tempo (em milissegundos) entre cada pulso durante o movimento.

    property HiTorq: boolean;
    Liga/desliga o modo de alto torque.

    Listagem da classe TRobotMove

    unit RobotMove;

    interface

    uses SysUtils, Classes, DateUtils, Forms, ExtCtrls,
         ParBib;

    type
      TRobotMove = class
      private
        lport: TLPT;
        tm: TTimer;
        FHiTorq: boolean;         // Ativa/desativa alto torque
        dvLeft, dvRight,          // divisor de frequencia
        psLeft, psRight: byte;    // pulsos
        fwLeft, fwRight: boolean; // direção
        onLeft, onRight: boolean; // anda / para
        baseCount: integer;       // contador base
        FBaseTime: cardinal;
        procedure OnTimer(Sender: TObject);
      public
        constructor Create(AOwner: TComponent; LPTPort: TLPT;
                           BaseTm: cardinal);
        destructor Destroy; override;
        procedure Ahead;
        procedure Back;
        procedure Stop;
        procedure Right;
        procedure Left;
        procedure VeryLeft;
        procedure VeryRight;
        procedure SpinLeft;
        procedure SpinRight;
        property PulseTime: cardinal read FBaseTime write FBaseTime;
        property HiTorq: boolean read FHiTorq write FHiTorq;
      end;

    implementation

    { TRobotMove }

    constructor TRobotMove.Create(AOwner: TComponent; LPTPort: TLPT;
                                  BaseTm: cardinal);
    begin
      inherited Create;
      lport:= LPTPort;
      SetLPT(lport);
      tm:= TTimer.Create(AOwner);
      tm.Enabled:= false;
      FBaseTime := BaseTm;
      tm.Interval:= FBaseTime;
      tm.OnTimer:= OnTimer;
      dvLeft:= 1;
      dvRight:= 1;
      psLeft:= 1;
      psRight:= 1;
      fwLeft:= true;
      fwRight:= true;
      baseCount := 1;
      onLeft:= false;
      onRight:= false;
      tm.Enabled:= true;
      FHiTorq := false;
    end;

    procedure TRobotMove.OnTimer(Sender: TObject);
    var pr, pl: byte;
    begin
      if (baseCount mod dvRight = 0) and onRight then
      begin
        if fwRight then
        begin
          if psRight = 8
            then psRight := 1
            else psRight := psRight shl 1;
        end
        else begin
          if psRight = 1
            then psRight := 8
            else psRight := psRight shr 1;
        end;
      end;
      if (baseCount mod dvLeft = 0) and onLeft then
      begin
        if fwLeft then
        begin
          if psLeft = 1
            then psLeft := 8
            else psLeft := psLeft shr 1;
        end
        else begin
          if psLeft = 8
            then psLeft := 1
            else psLeft := psLeft shl 1;
        end;
      end;

      if FHiTorq then
      begin
        pr := psRight or (psRight shl 1);
        if pr >= 16 then pr := psRight + 1;
        pl := psLeft or (psLeft shl 1);
        if pl >= 16 then pl := psLeft + 1;
        SetDataByte((pl shl 4) or pr);
      end
      else SetDataByte((psLeft shl 4) or psRight);
      Inc(baseCount);
      baseCount := baseCount mod 100000;
      tm.Interval:= FBaseTime;
    end;

    procedure TRobotMove.Ahead;
    begin
      onLeft:= true;
      onRight:= true;
      fwLeft:= true;
      fwRight:= true;
      dvLeft:= 1;
      dvRight:= 1;
    end;

    procedure TRobotMove.Back;
    begin
      onLeft:= true;
      onRight:= true;
      fwLeft:= false;
      fwRight:= false;
      dvLeft:= 1;
      dvRight:= 1;
    end;

    procedure TRobotMove.Stop;
    begin
      onLeft:= false;
      onRight:= false;
    end;

    procedure TRobotMove.Right;
    begin
      onLeft:= true;
      onRight:= true;
      fwLeft:= true;
      fwRight:= true;
      dvLeft:= 1;
      dvRight:= 2;
    end;

    procedure TRobotMove.Left;
    begin
      onLeft:= true;
      onRight:= true;
      fwLeft:= true;
      fwRight:= true;
      dvLeft:= 2;
      dvRight:= 1;
    end;

    procedure TRobotMove.VeryRight;
    begin
      onLeft:= true;
      onRight:= false;
      fwLeft:= true;
      fwRight:= true;
      dvLeft:= 1;
      dvRight:= 1;
    end;

    procedure TRobotMove.VeryLeft;
    begin
      onLeft:= false;
      onRight:= true;
      fwLeft:= true;
      fwRight:= true;
      dvLeft:= 1;
      dvRight:= 1;
    end;

    procedure TRobotMove.SpinRight;
    begin
      onLeft:= true;
      onRight:= true;
      fwLeft:= true;
      fwRight:= false;
      dvLeft:= 1;
      dvRight:= 1;
    end;

    procedure TRobotMove.SpinLeft;
    begin
      onLeft:= true;
      onRight:= true;
      fwLeft:= false;
      fwRight:= true;
      dvLeft:= 1;
      dvRight:= 1;
    end;

    destructor TRobotMove.Destroy;
    var tmp: TDateTime;
    begin
      tm.OnTimer:= nil;
      tm.Enabled:= false;
      tmp := IncMilliSecond(Now, tm.Interval+2);
      while tmp > Now do
        Application.ProcessMessages;
      tm.Free;
      SetDataByte(0);
    end;

    end.

    Programa de navegação e controle do robô

    O programa listado a seguir usa a classe TRobotMove para controlar o robô e fornece uma interface para o usuário. Basicamente o programa associa um botão na tela de interface a cada método fornecido pela classe. As funções de movimento também podem ser ativadas pelo teclado numérico. O tempo mostrado no canto inferior direito do form é o intervalo de tempo entre cada pulso enviado aos motores. Diminuir o tempo aumenta a velocidade do robô, mas existe um limite que varia de acordo com os motores utilizados e o peso do robô. Se usado um intervalo abaixo desse limite, os motores começam a perder passos ou simplesmente param. A figura 33 mostra o form da aplicação.
    As imagens que ilustram os botões foram omitidas da listagem para que a mesma não fique excessivamente longa. Como se trata de um form, foi incluído o arquivo dfm e o arquivo pas, além do arquivo de projeto.

    Figura 33: Tela do programa de navegação
    Arquivo de projeto RoboNav.dpr

    program RoboNav;
    uses
      Forms,
      Unit1 in 'Unit1.pas' {Form1},
      RobotMove in 'RobotMove.pas',
      ParBib in 'ParBib.pas';

    {$R *.res}
    begin
      Application.Initialize;
      Application.CreateForm(TForm1, Form1);
      Application.Run;
    end.

    Definição do form de interface, arquivo Unit1.dfm

    object Form1: TForm1
      Left = 269
      Top = 108
      Width = 528
      Height = 291
      Caption = 'Robô Nav'
      Color = clBtnFace
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'MS Sans Serif'
      Font.Style = [fsBold]
      OldCreateOrder = False
      OnCreate = FormCreate
      OnKeyPress = FormKeyPress
      PixelsPerInch = 96
      TextHeight = 13
      object Label1: TLabel
        Left = 16
        Top = 11
        Width = 64
        Height = 13
        Caption = 'Portas LPT'
      end
      object btOn: TButton
        Left = 13
        Top = 60
        Width = 112
        Height = 57
        Caption = 'Ativar'
        TabOrder = 0
        OnClick = btOnClick
        OnKeyPress = FormKeyPress
      end
      object btOff: TButton
        Left = 13
        Top = 124
        Width = 112
        Height = 57
        Caption = 'Desligar'
        Enabled = False
        TabOrder = 1
        OnClick = btOffClick
        OnKeyPress = FormKeyPress
      end
      object cbxPortas: TComboBox
        Left = 16
        Top = 32
        Width = 107
        Height = 21
        ItemHeight = 13
        ItemIndex = 0
        TabOrder = 2
        Text = 'LPT1'
        OnKeyPress = FormKeyPress
        Items.Strings = (
          'LPT1'
          'LPT2')
      end
      object pnMov: TPanel
        Left = 138
        Top = 32
        Width = 367
        Height = 222
        BevelOuter = bvNone
        Enabled = False
        TabOrder = 3
        object Label2: TLabel
          Left = 264
          Top = 136
          Width = 66
          Height = 13
          Caption = 'Tempo (ms)'
        end
        object btLeft: TBitBtn
          Left = 7
          Top = 6
          Width = 68
          Height = 66
          TabOrder = 0
          OnClick = btLeftClick
          OnKeyPress = FormKeyPress
        end
        object btAhead: TBitBtn
          Left = 79
          Top = 6
          Width = 68
          Height = 66
          TabOrder = 1
          OnClick = btAheadClick
          OnKeyPress = FormKeyPress
        end
        object btRight: TBitBtn
          Left = 151
          Top = 6
          Width = 68
          Height = 66
          TabOrder = 2
          OnClick = btRightClick
          OnKeyPress = FormKeyPress
        end
        object btVRight: TBitBtn
          Left = 151
          Top = 77
          Width = 68
          Height = 66
          TabOrder = 3
          OnClick = btVRightClick
          OnKeyPress = FormKeyPress
        end
        object btStop: TBitBtn
          Left = 79
          Top = 77
          Width = 68
          Height = 66
          TabOrder = 4
          OnClick = btStopClick
          OnKeyPress = FormKeyPress
        end
        object btVLeft: TBitBtn
          Left = 7
          Top = 77
          Width = 68
          Height = 66
          TabOrder = 5
          OnClick = btVLeftClick
          OnKeyPress = FormKeyPress
        end
       
       object btSLeft: TBitBtn
          Left = 7
          Top = 148
          Width = 68
          Height = 66
          TabOrder = 6
          OnClick = btSLeftClick
          OnKeyPress = FormKeyPress
        end
        object btBack: TBitBtn
          Left = 79
          Top = 148
          Width = 68
          Height = 66
          TabOrder = 7
          OnClick = btBackClick
          OnKeyPress = FormKeyPress
        end
        object btSRight: TBitBtn
          Left = 151
          Top = 148
          Width = 68
          Height = 66
          TabOrder = 8
          OnClick = btSRightClick
          OnKeyPress = FormKeyPress
        end
        object btTurbo: TBitBtn
          Left = 249
          Top = 6
          Width = 113
          Height = 105
          Caption = 'Turbo'
          TabOrder = 9
          OnClick = btTurboClick
          Layout = blGlyphTop
        end
        object seTime: TSpinEdit
          Left = 262
          Top = 152
          Width = 97
          Height = 22
          Enabled = False
          MaxValue = 100
          MinValue = 10
          TabOrder = 10
          Value = 35
          OnChange = seTimeChange
        end
      end
    end 


    Listagem do arquivo Unit1.pas

    unit Unit1;

    interface

    uses
      Forms, StdCtrls, Spin, Buttons, Controls, ExtCtrls, Classes,
      ParBib, RobotMove;

    type
      TForm1 = class(TForm)
        btOn: TButton;
        btOff: TButton;
        Label1: TLabel;
        cbxPortas: TComboBox;
        pnMov: TPanel;
        btLeft: TBitBtn;
        btAhead: TBitBtn;
        btRight: TBitBtn;
        btVRight: TBitBtn;
        btStop: TBitBtn;
        btVLeft: TBitBtn;
        btSLeft: TBitBtn;
        btBack: TBitBtn;
        btSRight: TBitBtn;
        btTurbo: TBitBtn;
        Label2: TLabel;
        seTime: TSpinEdit;
        procedure btOnClick(Sender: TObject);
        procedure btOffClick(Sender: TObject);
        procedure btTurboClick(Sender: TObject);
        procedure FormKeyPress(Sender: TObject; var Key: Char);
        procedure FormCreate(Sender: TObject);
        procedure btLeftClick(Sender: TObject);
        procedure btVLeftClick(Sender: TObject);
        procedure btSLeftClick(Sender: TObject);
        procedure btAheadClick(Sender: TObject);
        procedure btStopClick(Sender: TObject);
        procedure btBackClick(Sender: TObject);
        procedure btRightClick(Sender: TObject);
        procedure btVRightClick(Sender: TObject);
        procedure btSRightClick(Sender: TObject);
        procedure seTimeChange(Sender: TObject);
      private
        function LPTSelected: TLPT;
      public
        rob: TRobotMove;
      end;

    var
      Form1: TForm1;

    implementation

    {$R *.dfm}

    { TForm1 }

    function TForm1.LPTSelected: TLPT;
    begin
      case cbxPortas.ItemIndex of
        0: result := pLPT1;
        else result := pLPT2;
      end;
    end;

    procedure TForm1.btOnClick(Sender: TObject);
    begin
      rob:= TRobotMove.Create(self, LPTSelected, seTime.Value);
      btOff.Enabled:= true;
      btOn.Enabled:= false;
      pnMov.Enabled:= true;
    end;

    procedure TForm1.btOffClick(Sender: TObject);
    begin
      rob.Stop;
      rob.Free;
      btOn.Enabled:= true;
      btOff.Enabled:= false;
      pnMov.Enabled:= false;
    end;

    procedure TForm1.btTurboClick(Sender: TObject);
    begin
      rob.HiTorq := not rob.HiTorq;
      if rob.HiTorq
        then btTurbo.Caption := 'Turbo on'
        else btTurbo.Caption := 'Turbo off'
    end;

    procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
    begin
      case Key of
        '8': begin
          rob.Ahead;
          btAhead.SetFocus;
        end;
        '2': begin
          rob.Back;
          btBack.SetFocus;
        end;
        '5': begin
          rob.Stop;
          btStop.SetFocus;
        end;
        '7': begin
          rob.Left;
          btLeft.SetFocus;
        end;
        '9': begin
          rob.Right;
          btRight.SetFocus;
        end;
        '4': begin
          rob.VeryLeft;
          btVLeft.SetFocus;
        end;
        '6': begin
          rob.VeryRight;
          btVRight.SetFocus;
        end;
        '1': begin
          rob.SpinLeft;
          btSLeft.SetFocus;
        end;
        '3': begin
          rob.SpinRight;
          btSRight.SetFocus;
        end;
      end;
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
      seTime.Enabled:= true;
    end;

    procedure TForm1.btLeftClick(Sender: TObject);
    begin
      Rob.Left;
    end;

    procedure TForm1.btVLeftClick(Sender: TObject);
    begin
      rob.VeryLeft;
    end;

    procedure TForm1.btSLeftClick(Sender: TObject);
    begin
      rob.SpinLeft;
    end;

    procedure TForm1.btAheadClick(Sender: TObject);
    begin
      rob.Ahead;
    end;

    procedure TForm1.btStopClick(Sender: TObject);
    begin
      rob.Stop;
    end;

    procedure TForm1.btBackClick(Sender: TObject);
    begin
      rob.Back;
    end;


    procedure TForm1.btRightClick(Sender: TObject);
    begin
      rob.Right;
    end;

    procedure TForm1.btVRightClick(Sender: TObject);
    begin
      rob.VeryRight;
    end;

    procedure TForm1.btSRightClick(Sender: TObject);
    begin
      rob.SpinRight;
    end;

    procedure TForm1.seTimeChange(Sender: TObject);
    begin
      rob.PulseTime:= seTime.Value;
    end;

    end.



    Índice

    2) Visão geral do projeto
    3) Fonte de alimentação para testes de bancada
    4) A porta paralela
    5) Motores de passo
    6) Montagem dos circuitos
    7) Montagem do robô
    8) Alimentação
    9) Software de navegação
    10) Conclusão
    Apêndice - Duplicando polias e engrenagens