Robot - Segue Linha

Indice

O que é um robot segue linha?

Um robot segue linha é um veículo que segue uma linha que desenha um determinado trajeto no plano. Existem enumeras variações de robots segue linha, uns para seguir linhas pretas (o mais comum) outras para seguir linhas brancas, uns com mais sensores outros com menos, mas o objetivo é sempre o mesmo, seguir uma linha e o seu percurso no plano.

Qual o principio de funcionamento?

Este tipo de robot é munido de um conjunto de sensores que detecam a posição do robot em relação à linha, sendo usada esta informação para dar instruções aos motores para corrigir a sua trajetória quando esta foge do centro da linha.

O sensor mas o mais comumente usado é o Infra-vermelho.

Sensor Infravermelho.

O sensor infra-vermelho é constituído por um emissor de luz infra-vermelha e um detetor de luz infra-vermelha. Aproveitando o facto de que a luz é absorvida pelas superfícies escuras, a combinação destes dois componentes permite detetar uma superficie escura, no caso concreto uma linha preta, (ver figura 1)

figura 1

figura 2

Dispondo um conjunto de sensores IR perfilados, a que chamamos array de sensores,  conseguimos um indicador de referência em relação a uma linha preta. Existem enumeras configurações de arrays de sensores, uns com numero par de sensores, outros com numero impar uns com mais outros com menos. 

O código que se implementa para detetar a posição da linha tem de ter em conta o tipo de array de IR. A figura 2 mostra um array de 5 sensores IR. 

Como se pode observar pela figura 3 a posição da linha preta vai ser traduzida na deteção do sensor. Aqui também há 2 variantes. 

1ª - A linha preta é detetada como um sinal HIGH (1)

2ª - A linha preta é detetada como um sinal LOW (0)

Na figura podemos ver o funcionamento de um array de sensores IR cuja a deteção da linha é feita com um sinal HIGH 1. Ainda obervando a figura conseguimos ver que o robot está desviado para a esquerda

figura 3

Correção da trajetória.

Conforme explicado, o array de sensores permite, então, saber a posição relativa à linha preta do veículo, munidos desta informação, apenas é necessário dar instruções aos motores para acelerar ou desacelerar consoante a correção de trajetória que queremos.

Nas figuras 4 e 5 podemos ver representado um desvio para a direita e outro para a esquerda, respetivamente, assim como, pela representação das setas verdes e vermelhas a velocidade impressa aos motores para correção da trajetória.

A correção desta trajetória poderá ser feita, de uma forma mais profissional, com o uso do algoritmo PID. Para já faremos uma correção simples da trajetória.


figura 4

figura 5

E os motores?

Já vimos como se consegue detetar o desvio de um robot utilizando o um array de sensores IR e que esta informação servirá para aumentar ou diminuir a velocidade dos motores para efetuar a correção da trajetória.

Um conceito muito importante para entendermos como controlar a velocidade dos motores é o PWM (Pulse Width Modulation) 

figura 6

figura 7

PWM, o que é isto?

Imagine que liga um motor daqueles pequenos de brinquedos a uma bateria (ver figura 6), acho que é do entendimento geral que o motor vai começar a trabalhar, contudo a sua velocidade de rotação será constante.

Fazendo uma pequena alteração nas ligações, colocando um interruptor no circuito, e partindo do principio que conseguíamos, num velocidade grande, ligar e desligar o interruptor, íamos poder controlar a velocidade do motor, interrompendo e permitindo a passagem da corrente numa determinada frequência (ver figura 7)

Como não conseguimos, como humanos que somos, ligar e desligar, manualmente, o interruptor numa cadência que nos permitisse regular a velocidade do motor, substituímos este papel por um circuito eletrónico que simula este ligar e desligar do interruptor

figura 8

Na figura 8, temos  um circuito eletrónico PWM ligado ao motor.

Programando o controlador responsável por gerir o PWM, conseguimos definir a cadência dos impulsos, que permitirá, desta forma regular a velocidade do motor, ligando-o e desligando-o numa determinada cadência)

O PWM é usado um muitas soluções  na eletrónica aplicada, como por exemplo a regulação da intensidade do brilho de luzes LED. 

De facto, a regulação do brilho das lâmpadas LED, é conseguido ligando e desligando o circuito tão rápido que para o ser humano ficamos com a sensação que o LED brilha menos, na realidade ele desliga e liga a uma velocidade que engana a nossa vista/cérebro.

Os motores são ligados a um circuito a que chamamos de DRIVERS, isto porque as placas com os microcontroladores não têm potência de saída suficiente para aguentar com a corrente de um motor (havemos de abordar este tema numa outra oportunidade), mas na prática, um DRIVER, é um circuito intermédio que fica entre o motor e a placa microcontroladora que gera os impulsos PWM.

Estes drivers podem-se encontrar nas mais variadas formas e feitios, uns para motores mais potentes outro para motores menos potentes, uns para um só motor outros para dois motores, uns num circuito separado, outros embutidos na própria placa inde está o microcontrolador. Enfim, há uma panóplia deles cada um com as suas especificidades, as figuras 9,10,11 e 12 mostram alguns exemplos.


figura 9

DRIVER para dois motores DC de baixa potência

figura 10

DRIVER para dois motores DC de alta potência

figura 11

DRIVER para dois motores DC de baixa potência

figura 12

DRIVER para dois motores DC com microcontrolador incluido

Diagrama lógico.

De uma forma muito simplicista podemos representar a nossa lógica com o fluxograma da figura 13.

Resumindo. Se há um desvio para a esquerda, compensar a esquerda, se há um desvio para a direita, compensar a direita.

Não havendo desvios o robot segue com a mesma potência nas duas rodas

figura 13

Mãos à obra! Primeira etapa.

Para quem se está a iniciar na programação, aqui o lema é dividir para conquistar. Fazer as coisas por partes menores, testando cada uma das etapas, é meio caminho andado para se conseguir atingir em pleno o objetivo.

Então vamos começar pelo principal componente que nos vai permitir avaliar a nossa posição, o array de sensores IR. Para o efeito vamos utilizar a plataforma DOBOT AI-Starter, um carro robot que já vem equipado com um conjunto de sensores, desde IR, Cor, Luminosidade, Ultrasons, entre outros, figura 14 e 15.

figura 14

figura 15

Os pinos do microcontrolador.

Como é óbvio, tanto os sensores de IR como os motores estão ligados a pinos no microcontrolador, ou nos seus drivers correspondentes, nesta plataforma, o DOBOT-AI Starter, que tem por base um ARduino MEGA, os pinos dos motores e dos sensores IR são os seguintes:


IRed Sensors:


Motors:


Então a primeira etapa é fazer a leitura dos sensores IR e verificar se está a detetar, corretamente, a linha preta do circuito. Para tal vamos utilizar a linguagem de programação, mais comum para Arduíno, o C++.

Também vamos partir do principio que o leitor tem conhecimentos básicos da plataforma Arduíno,. Se não for este o caso aconselha-se que , visite a sua página oficial arduino.cc para mais informações. Também partimos do presuposto que o leitor tem conhecimentos básicos cd C++.

Código - 1ª parte - Sensores IR:

Primeiro inicializam-se as constantes com os número dos pinos onde estão conetados os sensores IR respetivamente.


//Constantes referentes aos pinos dos sensores IR.

const int IR1 = 25;

const int IR2 = 26;

const int IR3 = 27;

const int IR4 = 28;

const int IR5 = 29;

const int IR6 = 39;


Depois declaram-se as variáveis que irão guardar as leituras dos sensores, estas variáveis vão mudando de estado conforme é atualizada a leitura. Chamamos estas variáveis de variáveis de estado.


//Variaveis referentes ao estado dos sensores IR.

int stateIR1, stateIR2, stateIR3, stateIR4, stateIR5, stateIR6;


Implementa-se um função (boa prática) para atualizar as variáveis de estado declaradas anteriormente com a leitura digital da porta respetiva a cada um deles.


//Função que atualiza as variaveis de estado dos sensores

void updateIR() {

 stateIR1 = digitalRead(IR1);

 stateIR2 = digitalRead(IR2);

 stateIR3 = digitalRead(IR3);

 stateIR4 = digitalRead(IR4);

 stateIR5 = digitalRead(IR5);

 stateIR6 = digitalRead(IR6);

}


Com é tipico no Arduíno, na função setup(), inicializamos a porta Série, para podermos monitorizar os sensores e os pinos dos sensores.


void setup() {

 //Inicialização da porta serial.

 Serial.begin(115200);


 //Inicializa os pinos dos sensores IR como entrada.

 pinMode(IR1, INPUT);

 pinMode(IR2, INPUT);

 pinMode(IR3, INPUT);

 pinMode(IR4, INPUT);

 pinMode(IR5, INPUT);

 pinMode(IR6, INPUT);

}



Implementamos uma função para enviar para a Porta Série, a informação das variáveis de estado, para podermos monitorizar se os sensores estão a funcionar como esperado.


void printIR(){

Serial.print(stateIR1);

Serial.print(stateIR2);

        Serial.print(stateIR3);

        Serial.print(stateIR4);

        Serial.print(stateIR5);

        Serial.println(stateIR6);

}


Finalmente, na função loop do Arduino, vamos chamar as funções quee criamos para testar esta parte do código. Primeiro chamamos a função updateIR() para atualizar as variavéis de estado, depois chamamos a função printIR() para enviar para a porta série o valor destas mesmas variáveis.


void loop() {

   updateIR();

   printIR();

}


figura 16

1º Teste - Atualização dos sensores:

Depois de descarregar o código para o DOBOT-AI Starter, abrimos o monitor série e verificamos a leitura coorespondente

Verificamos que a leitra é 001100, o que significa que onde está 11 é a posição da linha preta, se virmos o nosso robot, de facto está correto, note, na figura 17, que os sensores do centrom ou seja o 3 e 4 estão, de facto, na linha preta. 

figura 17

NOTA:

Como a luz infravermelha é invisivel, a maioria dos sensores IR são munidos de um LED que replica o estado do sensor, se observar na figura 17, temos os 4 LEDs dos extremos acessos, indicando que não tem linha preta, enquanto que osdo centro estão apagados. Os LEDs são colocados para que o construtor possa ter uma referência visual do que se está a passar, o que dá muito jeito se há problemas no sensor.

figura 18

Se movermos o robot para fota da linha preta, verificamos que os indicadores visuais estão todos ligados (figura 18) e a leitura, no monitor Série, será de 000000, figura 19.


figura 19

Já temos detenção e já conseguimos saber a posição relativa do robot em relação à linha. 

Código - 2ª parte - Motores:

Primeiro inicializam-se as constantes com os número dos pinos onde estão conetados aos motores. Cada motor tem 2 pinos. Combinando os sinais que metemos nos pinos conseguimos controlar a velocidade (por PWM) e a direção se invertermos os sinais.


//Constantes referentes aos pinos dos motores.

const int MOTOR_RIGTH_PIN1 = 2;

const int MOTOR_RIGTH_PIN2 = 3;

const int MOTOR_LEFT_PIN1  = 4;

const int MOTOR_LEFT_PIN2  = 5;

 

NOTA:

Podemos verificar, com uma tabela de verdade, as combinações possíveis para os pinos dos motores e o seu efeito (figura 20):


figura 20

Posterirmente, na função setup() do Ardduíno, inicializam-se as portas onde estão ligados os pinos dos drivers dos motores para OUTPUT, pois a função destas portas é mandar para o DRIVER um determinado sinal.


 void setup() {

 //Inicialização da porta serial.

 Serial.begin(115200);


 //Inicializa os pinos dos sensores IR como entrada.

 pinMode(IR1, INPUT);

 pinMode(IR2, INPUT);

 pinMode(IR3, INPUT);

 pinMode(IR4, INPUT);

 pinMode(IR5, INPUT);

 pinMode(IR6, INPUT);


 //Inicializa os pinos dos motores como saída.

 pinMode(MOTOR_RIGTH_PIN1, OUTPUT);

 pinMode(MOTOR_RIGTH_PIN2, OUTPUT);

 pinMode(MOTOR_LEFT_PIN1, OUTPUT);

 pinMode(MOTOR_LEFT_PIN2, OUTPUT);

 }



Implementa-se uma função para fazer com que os motores andem para a frente. Anteriormente falamos em portas HIGH e LOW, mas como vamos usar PWM, o sinal LOW será 0 e o HIGH será entre 1 e 255, sendo que de robot para robot temos de testar valores mínimos e máximos. Este valor vai ser passado na função


//função para fazer o robô andar para frente com PWM

void andarFrente(int velocidade){

 analogWrite(MOTOR_RIGTH_PIN1, velocidade);

 analogWrite(MOTOR_RIGTH_PIN2, 0);

 analogWrite(MOTOR_LEFT_PIN1, velocidade);

 analogWrite(MOTOR_LEFT_PIN2, 0);

}


Na função loop() do Arduíno, chamamos a função andarFrente() passando o valor máximo de 255 e apagamos a chamada à função printIR() pois já não precisamos dela, só foi útil para verificar se os sensores estavam a funcionar como era esperado.

Como esta função comunica a baixa velocidade, via porta Série, mantermos a função iria fazer com o ciclo de repetição do programa fosse mais lento o que iria ter repercussões no efeito do PWM.


void loop() {

   updateIR();

   andarFrente(255);

}

Após descarregar o código para o robot, verificamos que temos rotação em ambas as rodas (ver animação 1).

animação 1

Verificamos também que a velocidade das rodas é demasiadamente excessiva, o que dificultaria a análise e resposta de sinais em tempo real. Isto varia consoante o tipo de motor. Neste caso, vamos admitir como velocidade máximo 180 e não os 255 que colocamos para teste. Este valor foi obtido por experimentação.

Este valor deve ser encontrado caso a caso, robot a robot, pois depende de alguns factores mecânicos, eletricos e físicos do robot.


Código - 3ª parte - Direita / Esquerda:

Agora vamos alterar a implementação da nossa função andarFrente() para que admita uma velocidade para cada roda de forma independente e vamos alterar o nome para movimentaRobot().

Repare que ela agora admite 2 parâmetros, a velocidade da roda direita e a da esquerda. Manipulando estes valores conseguimos fazer o carro mover-se para a direita e para a esquerda, aumentando e/ou diminuido a velocidade de rotação das rodas.


//função para fazer o robot virar para a direita ou esquerda

void movimentaRobot(int velocidade_roda_direita, int velocidade_roda_esquerda){

   analogWrite(MOTOR_RIGTH_PIN1, velocidade_roda_direita);

   analogWrite(MOTOR_RIGTH_PIN2, LOW);

   analogWrite(MOTOR_LEFT_PIN1, velocidade_roda_esquerda);

   analogWrite(MOTOR_LEFT_PIN2, LOW);

}


Código - 4ª parte - Correção de rota:

Agora vamos implementar a função segueLinha() que irá avaliar o estado dos sensores e corrigir a rota compensando na velocidade dos motores. 


//Função para fazer o robot corrigir a trajetória mediante leitura dos sensores

void segueLinha(){


   //Todos os sensores fora da linha o robot pára

   if(stateIR1 == 0 && stateIR2 == 0 && stateIR3 == 0 && stateIR4 == 0 && stateIR5 == 0 && stateIR6 == 0){

       movimentaRobot(0,0);

   }

   //Todos os sensores na linha o robot pára

   else if(stateIR1 == 1 && stateIR2 == 1 && stateIR3 == 1 && stateIR4 == 1 && stateIR5 == 1 && stateIR6 == 1){

       movimentaRobot(0,0);

   }

   //Os sensores centrais na linha o robot avança (velocidade igual nas duas rodas)

   else if(stateIR3 == 1 && stateIR4 == 1){

       movimentaRobot(100,100);

   }

   //Um desvio ligeiro para a esquerda é dada uma ligeira compensação para a direita, acelerando a roda esquerda

   else if(stateIR2 == 1 && stateIR3 == 1 ){

       movimentaRobot(0,100);

   }

   //Um desvio acentuado para a esquerda é dada uma acentuada compensação para a direita, acelerando a roda esquerda mais

   else if(stateIR1 == 1 && stateIR2 == 1){

       movimentaRobot(0,180);

   }

   //Um desvio ligeiro para a direita é dada uma ligeira compensação para a esquerda, acelerando a roda direita

   else if(stateIR4 == 1 && stateIR5 == 1){

       movimentaRobot(100,0);

   }

   //Um desvio acentuado para a direita é dada uma ligeira compensação para a direita, acelerando a roda direita

   else if(stateIR5 == 1 && stateIR6 == 1){

       movimentaRobot(180,0);

   }

}

Agora chamamos a nossa função no função loop() do Arduíno:



void loop() {

   updateIR();

   segueLinha();

}


E o nosso robot está pronto para ser testado!

Considerações finais.

Os valores passados na função movimentaRobot(), no caso variaram entre 100 e 180, são obtidos por experimentação. Como referido mais acima estes valores dependem de muitos factores, tais como tipo de motores, tipo de engrenagem, peso do robot, tensão de alimentação, entre outros.

O programa foi desenvolvido da forma mais simples possível par o efeito. Para um projeto mais "sério" deverão ser aplicados conceitos avançados de programação, tais como o uso de classes, objetos, enums, etc.