Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Manufacturing Technology >> Processo de manufatura

Robô seguidor de linha - Controle PID - Configuração do Android

Componentes e suprimentos

Arduino Nano R3
× 1
Sensor SparkFun RedBot - Seguidor de linha
× 1
Módulo Sensor TCRT5000 4CH Infrared Line Track Follower
× 1
Dispositivo Android
× 1
porta-bateria 4xAA
× 2
RobotGeek Servo de rotação contínua
× 2

Aplicativos e serviços online

Arduino IDE
MIT App Inventor 2

Sobre este projeto


O objetivo deste projeto é construir um Robô Seguidor de Linha com controle PID. Também usaremos um dispositivo Android para configurar facilmente os principais parâmetros de controle para um ajuste melhor e mais rápido.

Este projeto é o primeiro de um projeto mais complexo de 2 partes, onde minha intenção é explorar a potencialidade dos robôs seguidores de linha. Na 2ª parte:Robô Maze Solver, utilizando Inteligência Artificial com Arduino, o robô explorará e resolverá Labirintos, utilizando técnicas simples de inteligência artificial.

Abaixo está um vídeo que mostra o robô seguindo um circuito de linha:





Etapa 1:Lista de materiais


A lista de materiais necessários é muito simples e o robô final é muito barato (cerca de US $ 75,00):

Corpo (pode ser adaptado às suas necessidades):
  • 2 quadrados de madeira (80x80 mm)
  • 3 clipes de encadernação
  • 2 rodas de madeira (diâmetro:50 mm)
  • 1 lançador de bola
  • 9 bandas elásticas
  • Faixa de quadro de comando 3M
  • Juntas de plástico para correção do sensor
  • BreadBoard e fiação
  • 2 conjuntos de bateria de hidreto de metal 4XNi (5 V cada conjunto)
  • 2 X SM-S4303R de rotação contínua de plástico de 360 ​​graus servo
  • Arduino Nano
  • Módulo Bluetooth HC-06
  • 5 sensores de linha X (Módulo de sensor seguidor de trilha de linha infravermelha TCRT5000 4CH + 1 sensor de trilha independente)
  • 1 LED
  • 1 botão





Etapa 2:configuração dos motores


Para motores, foram usados ​​2 servos contínuos (SM-S4303R). Eles serão "colados" juntos formando um bloco único e sólido como você pode ver na foto (use a tira Command da 3M, cola ou fita dupla face). Esses servos funcionarão em uma determinada velocidade, definida pela largura de pulso recebida em sua entrada de dados. Para este servo específico, a largura de pulso vai de 1,0 ms (1.000 microssegundos) a 2,0 ms (2.000 microssegundos). Outros servos podem trabalhar com larguras de pulso diferentes.

Olhando em detalhes:
  • Um pulso de 1,5 ms irá posicionar o servo na posição neutra, ou “parado”.
  • Um pulso de 1,0 ms comandará o servo em velocidade total (cerca de 70 RPM) em uma direção
  • Um pulso de 2,0 ms em velocidade total na direção oposta.
  • Pulso entre 1,0 e 1,5 ms ou 1,5 ms e 2,0 ms, gerará velocidade proporcional.

Depois de ter ambos os servos fisicamente conectados, siga o circuito de desenho acima para alimentá-los (5 V ou 6 V externos) e alimente-os com o sinal do Arduino:
  • Servo esquerdo:Arduino Pin 5
  • Servo direito:Arduino Pin 3

Depois de todos conectados, a primeira coisa que deve ser feita, é enviar um pulso de 1,5ms para verificar se os motores estão "parados" (sem funcionar). Caso contrário, os servos devem ser ajustados para parada total (procure o parafuso amarelo, abaixo do servo).

NOTA :Se o seu servo não possui este ajuste físico, tente alterar o parâmetro "1500" microssegundos dentro da função (para cima ou para baixo) até obter o ponto final.

O código do Arduino abaixo pode fazer o trabalho:
  #include  // Biblioteca de servo Servo leftServo; Servo rightServo; Configuração void () {leftServo.attach (5); rightServo.attach (3); leftServo.writeMicroseconds (1500); rightServo.writeMicroseconds (1500);} void loop () {}  





Etapa 3:monte a carroceria e os motores para o teste de movimento

  • Com a tira da moldura do 3M Command, fixe os 2 Servos ao da peça de madeira quadrada.
  • Fixe a 2ª madeira quadrada à anterior usando os clipes de encadernação. Ajuste o comprimento da plataforma às suas necessidades.
  • Fixe o lançador de bolas usando o clipe de encadernação.
  • A fonte de alimentação para os motores virá de um dos conjuntos de baterias de 5V. Este conjunto de bateria será instalado entre a placa de ensaio e a estrutura do corpo.
  • Conecte a bateria a ser usada com servos:esquerda da rede elétrica lateral exclusivamente para fonte de servos
  • Conecte o Arduino Nano à placa de ensaio
  • Conecte o GND da rede elétrica ao GND do Arduino.
  • Conecte os Servos ao Arduino:LEFT ==> Pino 5; RIGHT ==> Pin 3
  • Conecte o LED ao Arduino Pin 13
  • Conecte o botão ao Arduino Pin 9

Observe que, devido à forma como os servos são montados (em oposição), a faixa de velocidade é:
  • A velocidade de avanço do servo direito vai de 1.500us (parado) a 2.000us (velocidade total)
  • A velocidade de avanço do servo esquerdo vai de 1.500us (parado) a 1.000 (velocidade total)

Um LED externo é adicionado ao pino 13, para fins de sinalização e teste (você pode usar o LED interno do Arduino, ao invés de um externo se quiser, mas leve em consideração que será difícil vê-lo no meio dos cabos).

Além disso, um botão está conectado ao pino 9. Este botão é muito útil para fins de teste e para a inicialização do robô.

Por exemplo:
  while (digitalRead (buttonPin)) {} motorTurn (LEFT, 500); motorTurn (RIGHT, 500);  

Observe que as 2 linhas que irão comandar o Robô para virar à ESQUERDA, esperar 500ms e virar à DIREITA só acontecerão após você pressionar o botão (buttonPin =0). Antes disso, o programa será interrompido no loop infinito.

O código abaixo pode ser usado como base para um teste completo do motor (para frente, para trás, parada total, vire à esquerda, vire à direita). Se necessário, você deve ajustar os atrasos para o ângulo de giro necessário dependendo de seus motores (também, às vezes, os valores dos pulsos esquerdo e direito devem ser um pouco diferentes para compensar qualquer falta de equilíbrio dos motores.
FDDQRQOIN4TTVY0.ino





Etapa 4:o módulo Bluetooth (opcional)


O módulo Bluetooth HC-06 deve ser instalado na placa de ensaio conforme mostrado no desenho. A biblioteca SoftSerial do Arduino será usada.

Abaixo das conexões de pinos do HC-06:
  • Pin Tx para Arduino pino 10 (Rx)
  • PIN RX para Arduino pino 11 (Tx)
  • VCC / GND para Arduino 5V / GND

O robô funcionará com ou sem Bluetooth. O código é construído de forma que, se você não ativar o BT, os parâmetros padrão serão aqueles a serem usados ​​pelo robô. Portanto, não se preocupe se você preferir não instalar o módulo HC-06, o código ainda funcionará bem. Na última parte deste tutorial, explorarei como usar um App Android para enviar dados para melhor ajuste dos parâmetros do robô e / ou mover o robô no modo manual. Deixarei o uso do Bluetooth e do App como opcional caso alguém queira explorar mais a utilização de um Line Follower Robot para competições, por exemplo.





Etapa 5:adicionar os sensores de linha


Conecte os cabos aos pinos do Arduino conforme abaixo:
  • Sensor 0 =12
  • Sensor 1 =18
  • Sensor 2 =17
  • Sensor 3 =16
  • Sensor 4 =19
  • Fixe os 5 sensores em uma barra de plástico conforme mostrado nas fotos
  • É aconselhável rotular os sensores para fins de teste. O nome dos sensores vai de "0" (mais à esquerda) a "4" (mais à direita)
  • Passe os cabos por baixo da moldura, usando os elásticos para fixá-los. Tome cuidado para não se confundir com as rodas ou Caster.
  • Consertou o segundo conjunto de baterias de 5 V e conectou-o ao Arduino Vin.

No meu caso utilizo um módulo com 4 sensores integrados + 1 extra. Todos eles são compatíveis. Para simplificar, no diagrama eu incluí 5 sensores autônomos conectados entre si. Os resultados finais são os mesmos em ambas as configurações.





Etapa 6:Implementando a Lógica do Sensor IR


O sensor IR consiste em um LED IR individual e um fotodiodo IR. A luz infravermelha emitida pelo LED atinge a superfície e é refletida de volta para o fotodiodo infravermelho. O fotodiodo então gera uma tensão de saída proporcional ao nível de refletância da superfície (valores maiores para "superfícies claras" e menores para "superfícies pretas / escuras").

No caso dos sensores utilizados, um circuito integrado no módulo gera como saída um sinal digital simples (HIGH:Dark; LOW:Light). Um potenciômetro instalado no módulo (ver foto) irá ajustar o nível correto de luz para ser considerado "escuro" ou "claro". Funciona de forma que quando a cor da luz refletida é preto / escuro, um nível digital ALTO ("1") é gerado em sua saída e um nível BAIXO ("0") para outra cor mais clara. Usei aqui um módulo integrado com 4 sensores e um módulo extra com um único sensor (formato diferente, mas mesma lógica). A combinação é um array de 5 sensores que eu achei bom para um controle bom e suave, como explicado abaixo.

A matriz de 5 sensores é montada de forma que se apenas um sensor estiver centralizado em relação à linha preta, apenas aquele sensor específico produzirá um ALTO. Por outro lado, o espaço entre os sensores deve ser calculado para permitir que 2 sensores possam cobrir toda a largura da linha preta simultaneamente, produzindo também um ALTO em ambos os sensores (veja as fotos acima).

A possível saída da matriz do sensor ao seguir uma linha são:
  • 0 0 0 0 1
  • 0 0 0 1 1
  • 0 0 0 1 0
  • 0 0 1 1 0
  • 0 0 1 0 0
  • 0 1 1 0 0
  • 0 1 0 0 0
  • 1 1 0 0 0
  • 1 0 0 0 0

Possuindo 5 sensores, permite a geração de uma "variável de erro" que ajudará a controlar a posição do robô sobre a linha, conforme mostrado a seguir.

Vamos considerar que a condição ótima é quando o robô está centrado, tendo a linha logo abaixo do "sensor do meio" (Sensor 2). A saída do array será:0 0 1 0 0 e nesta situação, o "erro" será "zero". Se o robô começar a se mover para a esquerda (a linha "parece se mover" para a direita) o erro deve aumentar com um sinal positivo. Se o robô começar a se mover para a direita (a linha "parece se mover" para a esquerda), no da mesma forma, o erro deve aumentar, mas agora com sinal negativo.

A variável de erro, relacionada com o status do sensor será:

0 0 1 0 0 ==> Erro =0
  • 0 0 0 0 1 ==> Erro =4
  • 0 0 0 1 1 ==> Erro =3
  • 0 0 0 1 0 ==> Erro =2
  • 0 0 1 1 0 ==> Erro =1
  • 0 1 1 0 0 ==> Erro =-1
  • 0 1 0 0 0 ==> Erro =-2
  • 1 1 0 0 0 ==> Erro =-3
  • 1 0 0 0 0 ==> Erro =-4

Olhando para o código do Arduino, cada um dos sensores será definido com um nome específico (considere que o sensor Line Follow mais à esquerda deve ser atribuído com um rótulo "0"):
  const int lineFollowSensor0 =12; const int lineFollowSensor1 =18; const int lineFollowSensor2 =17; const int lineFollowSensor3 =16; const int lineFollowSensor4 =19;  

Para armazenar os valores de cada sensor, uma variável de matriz será criada:
  int LFSensor [5] ={0, 0, 0, 0, 0};  

Cada posição do array será constantemente atualizada com a saída de cada um dos sensores:
  LFSensor [0] =digitalRead (lineFollowSensor0); LFSensor [1] =digitalRead (lineFollowSensor1); LFSensor [2] =digitalRead (lineFollowSensor2); LFSensor [3] =digitalRead (lineFollowSensor3); =digitalRead (lineFollowSensor4);  

Tendo o valor de cada um dos sensores, uma lógica deve ser implementada para gerar a variável de erro:
  if ((LFSensor [0] ==0) &&(LFSensor [1] ==0) &&(LFSensor [2] ==0) &&(LFSensor [3] ==0) &&(LFSensor [4] ==1)) erro =4; else if ((LFSensor [0] ==0) &&(LFSensor [1] ==0) &&(LFSensor [2] ==0) &&(LFSensor [3] ==1) &&(LFSensor [4] ==1)) erro =3; else if ((LFSensor [0] ==0) &&(LFSensor [1] ==0) &&(LFSensor [2] ==0) &&(LFSensor [3] ==1) &&(LFSensor [4] ==0)) erro =2; else if ((LFSensor [0] ==0) &&(LFSensor [1] ==0) &&(LFSensor [2] ==1) &&(LFSensor [3] ==1) &&(LFSensor [4] ==0)) erro =1; else if ((LFSensor [0] ==0) &&(LFSensor [1] ==0) &&(LFSensor [2] ==1) &&(LFSensor [ 3] ==0) &&(LFSensor [4] ==0)) erro =0; else if ((LFSensor [0] ==0) &&(LFSensor [1] ==1) &&(LFSensor [2] ==1) &&(LFSensor [3] ==0) &&(LFSensor [4] ==0)) erro =- 1; else if ((LFSensor [0] ==0) &&(LFSensor [1] ==1 ) &&(LFSensor [2] ==0) &&(LFSensor [3] ==0) &&(LFSensor [4] ==0)) erro =-2; else if ((LFSensor [0] ==1) &&(LFSensor [1] ==1) &&(LFSensor [2] ==0) &&(LFSensor [3] ==0) &&(LFSensor [4] ==0)) erro =-3; else if ((LFSensor [0] ==1) &&(LFSensor [1] ==0) &&(LFSensor [2] ==0) &&(LFSensor [3] ==0) &&(LFSensor [4] ==0)) erro =-4;  





Etapa 7:Controle de direção (Controle Proporcional - P)


Perfeito! Neste ponto, nosso robô está montado e operacional. Você deve realizar alguns testes básicos com os motores, ler a saída dos sensores e testá-los em uma linha. O que falta é o verdadeiro "cérebro", os primeiros passos de uma "inteligência artificial". Faremos isso, implementando uma lógica de controle que garantirá que o Robô continuará seguindo a linha.

Controle Proporcional Simples:

Suponha que o robô esteja correndo sobre uma linha e a saída do Sensor Array seja: "0 0 1 0 0" . O erro correspondente é "0". Nessa situação, os dois motores devem funcionar para frente com velocidade constante.

Por exemplo:

Definindo a variável: iniMotorSpeed ​​=250 ; significa que o servo ESQUERDO receberá pulsos de 1.250us e o servo DIREITO 1.750us. Com esses parâmetros, o robô se moverá para frente na metade da velocidade. Lembre-se de que a velocidade de avanço do servo DIREITO variará com o comprimento de pulso de 1.500us (parado) a 2.000us (velocidade total) e o servo ESQUERDO de 1.500us (parado) a 1.000us (velocidade total).
  rightServo.writeMicroseconds (1500 + iniMotorPower); leftServo.writeMicroseconds (1500 - iniMotorPower);  

Suponha agora que o Robô dirigido para a esquerda (é como o "LINHA vai para a direita") e também cobriu o sensor 3. A saída do Array será: "0 0 1 1 0" e o erro =1 . Nesta situação, o que você precisa é virar o robô para a direita. Para fazer isso, você deve diminuir a velocidade do servo RIGHT, o que significa diminuir o comprimento do pulso. Além disso, a velocidade do servo ESQUERDO deve aumentar, o que significa diminuir o comprimento do pulso do servo ESQUERDO. Para fazer isso, precisamos alterar a função de controle do motor:
  rightServo.writeMicroseconds (1500 + iniMotorPower - erro); ==> Erro positivo:diminui velocityleftServo.writeMicroseconds (1500 - iniMotorPower - erro); ==> Erro positivo:aumentar a velocidade  

A lógica acima está correta, mas é fácil entender que adicionar ou subtrair "1" microssegundo na duração do pulso não gerará a correção necessária em um tempo realístico. É intuitivo que o número a ser adicionado ou subtraído seja maior, por exemplo 50, 100, etc. Para isso, o "erro" deve ser multiplicado por uma constante (vamos chamá-lo de "K"). Uma vez que a influência desta constante será proporcional ao erro, iremos chamá-la de "Constante Proporcional:Kp" .

A função motora será:
  int Kp =50; rightServo.writeMicroseconds (1500 + iniMotorPower - erro Kp *); leftServo.writeMicroseconds (1500 - iniMotorPower - erro Kp *);  

Podemos resumir o que acontecerá com os motores conforme mostrado abaixo:
  • Matriz de sensores: 0 0 1 0 0 ==> erro =0 ==> Comprimento do pulso do servo direito =1.750us ==> Comprimento do pulso do servo esquerdo =1.250us (ambos os motores na mesma velocidade)
  • Matriz de sensores: 0 0 1 1 0 ==> erro =1 ==> Comprimento do pulso do servo direito =1.700us (mais lento) ==> Comprimento do pulso do servo esquerdo =1.200us (mais rápido)

Se a situação for oposta e o robô for direcionado para a direita, o erro seria "negativo" e a velocidade dos servos deveria mudar:
  • Matriz de sensores: 0 0 1 0 0 ==> erro =0 ==> Comprimento do pulso do servo direito =1.750us ==> Comprimento do pulso do servo esquerdo =1.250us (ambos os motores na mesma velocidade)
  • Matriz de sensores: 0 1 1 0 0 ==> erro =-1 ==> Comprimento do pulso do servo direito =1.800us (mais rápido) ==> Comprimento do pulso do servo esquerdo =1.300us (mais lento)

Neste ponto fica claro que quanto mais o Robô for direcionado para um lado, maior será o erro e mais rápido deverá retornar ao centro. A velocidade com que o Robô reagirá ao erro será proporcional a ele. Isso é chamado de "Controle Proporcional" , que é o componente "P" de uma rede de controle mais complexa, o PDI (Proporcional, Derivativo, Integral).





Etapa 8:Controle PID (opcional)


Caso você queira pular para esta parte, também está OK. Você pode ficar com o controle proporcional explicado na última etapa, ou queimar alguns cérebros para implementar um sistema de controle mais complexo em seu robô, a escolha é sua.

Se você se decidiu, vamos lá!

PID (Proporcional, Derivativo e Integral) é um dos esquemas de controle mais comuns. A maioria dos loops de controle industrial usa algum tipo de controle PID. Existem muitas maneiras de sintonizar um loop PID, incluindo a técnica manual usada neste exemplo.

Pense no PID como uma simples mola. Uma mola tem um comprimento original, que quando perturbado por expansão ou contração, tende a recuperar seu comprimento original no menor tempo possível. Da mesma forma, um algoritmo PID em um sistema tem um valor definido de uma quantidade física particular a ser controlada, chamado de ‘ ponto de ajuste ', Que quando alterado por algum motivo, o sistema controla os outros recursos necessários nele, para voltar ao ponto de ajuste original no menor tempo possível. Os controladores PID são usados ​​sempre que houver necessidade de controlar uma quantidade física e torná-la igual a um valor especificado. Exemplo, Cruise Controller em carros, robôs, reguladores de temperatura, reguladores de tensão, etc.





Como funciona o PID?


O sistema calcula o ‘ erro ’, Ou‘ desvio 'Da quantidade física a partir do ponto de ajuste, medindo o valor atual dessa quantidade física usando um sensor (es). Para voltar ao ponto de ajuste, este ‘ erro 'Deve ser minimizado, e idealmente deve ser igual a zero. Além disso, esse processo deve acontecer o mais rápido possível. Idealmente, deve haver atraso zero na resposta do sistema à mudança em seu ponto de ajuste.

Mais informações podem ser encontradas em diversos livros e sites, inclusive aqui.





Implementando PID


i) Termo de erro (e):

Isso é igual à diferença entre o ponto de ajuste e o valor atual da quantidade que está sendo controlada. Erro = set_point - current_value (no nosso caso é a variável de erro obtida da posição do robô sobre a linha

ii) Termo Proporcional (P):

Este termo é proporcional ao erro.

P =erro

Este valor é responsável pela magnitude da mudança necessária na quantidade física para atingir o ponto de ajuste. O termo de proporção é o que determina o tempo de subida da malha de controle ou a rapidez com que atingirá o ponto de ajuste.

iii) Termo Integral (I):

Este termo é a soma de todos os valores de erro anteriores.

I =I + erro

Este valor é responsável pela rapidez de resposta do sistema à mudança do set point. O termo integral é usado para eliminar o erro de estado estacionário exigido pelo termo proporcional. Normalmente, pequenos robôs não usam o termo integral porque não estamos preocupados com o erro de estado estacionário e isso pode complicar o " ajuste de loop "

iv) Termo Diferencial ou Derivado (D):

Este termo é a diferença entre o erro instantâneo do set point e o erro do instante anterior.

D =erro - previousError

Este valor é responsável por desacelerar a taxa de variação da quantidade física quando se aproxima do ponto de ajuste. O termo derivado é usado para reduzir o overshoot ou quanto o sistema deve " over correct "

Equação:

PIDvalue =(Kp * P) + (Ki * I) + (Kd * D)

Onde:

Kp é a constante usada para variar a magnitude da mudança necessário para atingir o ponto de ajuste. Ki é a constante usada para variar a taxa na qual a mudança deve ser trazido na quantidade física para atingir o ponto de ajuste. Kd é a constante usada para variar a estabilidade do sistema.

Uma abordagem para ajustar o loop pode ser o Método experimental de tentativa de erro :

Defina a variável Kd para 0 e ajuste primeiro o termo Kp sozinho. Kp de 25 é um bom ponto de partida no nosso caso aqui. Na última etapa usamos um Kp de 50 que funciona muito bem com o meu Robot. Assim que o robô responder razoavelmente, ajuste a parte derivada do loop de controle ( Kd ) Primeiro, defina os valores Kp e Kd cada um para 1/2 do valor Kp. Por exemplo, se as respostas do robô forem razoáveis ​​com um Kp =50, defina Kp =25 e Kd =25 para iniciar. Aumente o ganho Kd (derivado) para diminuir o overshoot, diminua-o se o robô se tornar instável.
  • Se o robô reagir muito lentamente, aumente o valor.
  • Se o robô parecer reagir rapidamente tornando-se instável, diminua o valor.

Um outro componente do loop a considerar é a Taxa de Amostra / Loop real . Acelerar ou desacelerar esse parâmetro pode fazer uma diferença significativa no desempenho do robô. Isso é definido pelo atraso declarações que você tem em seu código. É um método de tentativa de erro de tentativa para obter o resultado ideal.

Com base na abordagem acima, a função abaixo foi implementada:
  void calculPID () {P =erro; I =I + erro; D =erro anteriorError; Valor PID =(Kp * P) + (Ki * I) + (Kd * D); previousError =erro;}  

A constante Kp simples usada na última etapa será substituída por este PIDvalue mais completo :
  void motorPIDcontrol () {int leftMotorSpeed ​​=1500 - iniMotorPower - PIDvalue; int rightMotorSpeed ​​=1500 + iniMotorPower - valor PID; leftServo.writeMicroseconds (leftMotorSpeed); rightServo.writeMicroseconds (rightMotorSpeed);}  

Mas note que se você tiver Kd e Ki =0 , PIDvalue é apenas o erro Kp * usado na última etapa.





Etapa 9:o código final


Nesta etapa, o robô pode seguir um loop constante e o fará sem parar. O programa de loop seria:
  void loop () {readLFSsensors (); // lê os sensores, os valores de armazenamento no Sensor Array e calcula o "erro" calculePID (); motorPIDcontrol ();}  

Mas para uma operação mais completa e real, é importante adicionar pelo menos alguns " comandos básicos "feito" com a linha ". Por exemplo, vamos introduzir uma nova variável:" modo ". Vamos definir 3 estados para esta variável:

Modo:
  • #define STOPPED 0
  • #define FOLLOWING_LINE 1
  • #define NO_LINE 2

Se todos os sensores encontrarem uma linha preta, a saída do Sensor Array seria:1 1 1 1 1. Nesta condição, podemos definir o modo como "STOPPED" e o robô deve realizar uma " parada total "
  if ((LFSensor [0] ==1) &&(LFSensor [1] ==1) &&(LFSensor [2] ==1) &&(LFSensor [3] ==1) &&(LFSensor [4] ==1)) {mode =STOPPED;}  

Outra situação comum com robôs de linha seguidora é onde ele encontra " nenhuma linha ", ou a saída do Sensor Array é:0 0 0 0 0. Neste caso, podemos programá-lo para voltar 180o ou em pequenos ângulos até que uma linha seja encontrada e a condição Line Follow normal seja retomada.
  else if ((LFSensor [0] ==0) &&(LFSensor [1] ==0) &&(LFSensor [2] ==0) &&(LFSensor [3] ==0) &&( LFSensor [4] ==0)) {mode =NO_LINE;}  

O loop () completo seria:
  void loop () {readLFSsensors (); switch (modo) {case STOPPED:motorStop (); pausa; case NO_LINE:motorStop (); motorTurn (ESQUERDA, 180); pausa; case FOLLOWING_LINE:calculePID (); motorPIDcontrol (); pausa; }}  

O código final real irá integrar alguma lógica adicional e também algumas variáveis ​​que devem ser inicializadas, etc. Durante a explicação acima eu os deixei de fora para simplificar, mas tudo deve estar claro olhando para o código final.

Abaixo está o código final do Arduino:
FUXCUEAIN699SZC.ino FLD2J3KIN699SZF.h FOFYXFZIN699SZT.ino FMPX9KJIN699SZU.ino FFE5AZ3IN699T06.ino





Etapa 10:Ajustando o controle PID usando o aplicativo Android


No código anterior, você pode encontrar em " robotDefines.h "aba as seguintes definições para as constantes a serem usadas com o controle PID:
float Kp=50;float Ki=0;float Kd=0; 

As explained at previous step, the best way to define the correct constant to be used with a PID controller is using the "Try-error" methodology. The bad side of that is that you must re-compile the program each time that you must change it. One way to speed-up the process is to use the Android App to send the constants at the "Set-Up Phase" .

I developed an Android App exclusively for that. In short there are the traditional manual commands:
  • FW, BW, Left, Right and Stop where the app will send respectively to the BT module:'f', 'b', 'l', 'r' and 's'.

Also 3 sliders were included, one for each PID constants:
  • Kd:"d/XXX" where "XXX" it is a number from 0 to 100.
  • Kp:"p/XXX"
  • Ki:"i/XXX"

An extra button was included that will work exactly as the button connected on Arduino Pin9. You can use one or the other, it does not matter.

Below you can find the .aia file that can be modified at MIT AppInventor and the .apk file to be installed directly in your Android device.
FTH62BVIN699T4B.aia F60H7R0IN699T4I.apk





Step 11:Changing the Code for PID remote tuning


During the Setup, we will introduce a loop where you can send the PID parameters to the Robot before you put him over the line:
 while (digitalRead(buttonPin) &&!mode) { checkBTcmd(); // verify if a comand is received from BT remote control manualCmd (); command =""; } checkPIDvalues(); mode =STOPPED; 

The manual command function will be:
void manualCmd(){ switch (command[0]) { case 'g':mode =FOLLOWING_LINE; pausa; case 's':motorStop(); //turn off both motors break; case 'f':motorForward(); pausa; case 'r':motorTurn(RIGHT, 30); motorStop(); pausa; case 'l':motorTurn(LEFT, 30); motorStop(); pausa; case 'b':motorBackward(); pausa; case 'p':Kp =command[2]; pausa; case 'i':Ki =command[2]; pausa; case 'd':Kd =command[2]; pausa; }}  

In the video, you can see some tests using the Android App. Below the final code including the PID setup via Android:
FGAEB9BIN7QQQAW.ino FBMONSNIN7QQQCD.ino F8B3CDHIN7QQQCL.h FNOMRUNIN7QQQCP.ino FA3K57ZIN7QQQCR.ino





Step 12:Conclusion


This is the first part of a more complex project, exploring the potentiality of a line follower robot. In the next part, I will develop a Maze solve robot, based on this this project here. Hopefully I can contribute for others to learn more about electronics, robot, Arduino, etc.

The update files for this project can be found at GITHUB. For more tutorials, please visit my Blog:MJRoBot.org

Greetings from the south of the world!

Obrigado

Marcelo

Código

  • Snippet de código # 1
  • Snippet de código # 2
  • Snippet de código # 3
  • Code snippet #5
  • Code snippet #6
  • Code snippet #10
  • Code snippet #11
  • Code snippet #12
  • Code snippet #15
  • Code snippet #17
  • Code snippet #18
Snippet de código # 1 Texto simples
#include  // Servo library Servo leftServo;Servo rightServo;Void setup(){ leftServo.attach(5); rightServo.attach(3); leftServo.writeMicroseconds(1500); rightServo.writeMicroseconds(1500);}void loop(){}
Snippet de código # 2 Texto simples
while(digitalRead(buttonPin)) { }motorTurn (LEFT, 500);motorTurn (RIGHT, 500);
Snippet de código # 3 Texto simples
const int lineFollowSensor0 =12;const int lineFollowSensor1 =18;const int lineFollowSensor2 =17;const int lineFollowSensor3 =16;const int lineFollowSensor4 =19;
Code snippet #5Plain text
LFSensor[0] =digitalRead(lineFollowSensor0);LFSensor[1] =digitalRead(lineFollowSensor1);LFSensor[2] =digitalRead(lineFollowSensor2);LFSensor[3] =digitalRead(lineFollowSensor3);LFSensor[4] =digitalRead(lineFollowSensor4);
Code snippet #6Plain text
if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==0 )&&(LFSensor[3]==0 )&&(LFSensor[4]==1 )) error =4;else if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==0 )&&(LFSensor[3]==1 )&&(LFSensor[4]==1 )) error =3; else if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==0 )&&(LFSensor[3]==1 )&&(LFSensor[4]==0 )) error =2;else if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==1 )&&(LFSensor[3]==1 )&&(LFSensor[4]==0 )) error =1;else if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==1 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) error =0;else if((LFSensor[0]==0 )&&(LFSensor[1]==1 )&&(LFSensor[2]==1 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) error =- 1;else if((LFSensor[0]==0 )&&(LFSensor[1]==1 )&&(LFSensor[2]==0 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) error =-2;else if((LFSensor[0]==1 )&&(LFSensor[1]==1 )&&(LFSensor[2]==0 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) error =-3;else if((LFSensor[0]==1 )&&(LFSensor[1]==0 )&&(LFSensor[2]==0 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) error =-4;
Code snippet #10Plain text
void calculatePID(){ P =error; I =I + error; D =error-previousError; PIDvalue =(Kp*P) + (Ki*I) + (Kd*D); previousError =error;}
Code snippet #11Plain text
void motorPIDcontrol(){ int leftMotorSpeed =1500 - iniMotorPower - PIDvalue; int rightMotorSpeed =1500 + iniMotorPower - PIDvalue; leftServo.writeMicroseconds(leftMotorSpeed); rightServo.writeMicroseconds(rightMotorSpeed);}
Code snippet #12Plain text
void loop (){ readLFSsensors(); // read sensors, storage values at Sensor Array and calculate "error" calculatePID(); motorPIDcontrol();}
Code snippet #15Plain text
void loop() { readLFSsensors(); switch (mode) { case STOPPED:motorStop(); pausa; case NO_LINE:motorStop(); motorTurn(LEFT, 180); pausa; case FOLLOWING_LINE:calculatePID(); motorPIDcontrol(); pausa; }} 
Code snippet #17Plain text
 while (digitalRead(buttonPin) &&!mode) { checkBTcmd(); // verify if a comand is received from BT remote control manualCmd (); command =""; } checkPIDvalues(); mode =STOPPED;
Code snippet #18Plain text
void manualCmd(){ switch (command[0]) { case 'g':mode =FOLLOWING_LINE; pausa; case 's':motorStop(); //turn off both motors break; case 'f':motorForward(); pausa; case 'r':motorTurn(RIGHT, 30); motorStop(); pausa; case 'l':motorTurn(LEFT, 30); motorStop(); pausa; case 'b':motorBackward(); pausa; case 'p':Kp =command[2]; pausa; case 'i':Ki =command[2]; pausa; case 'd':Kd =command[2]; pausa; }} 
Github
https://github.com/Mjrovai/MJRoBot-Line-Followerhttps://github.com/Mjrovai/MJRoBot-Line-Follower

Esquemas

oIDhLcHQ30lDgVBXZvb8.fzz

Processo de manufatura

  1. O Futuro da Robótica
  2. Sensor de rastreamento de linha com RPi
  3. Sensor Raspberry Pi e controle do atuador
  4. ROBÔ WIFI RASPBERRY PI CONTROLADO PELO TELEFONE INTELIGENTE ANDROID
  5. Automação:Linha do robô redesenhada
  6. Linha do robô SCARA expandida
  7. Controle remoto universal usando Arduino, 1Sheeld e Android
  8. Seguidor de linha industrial para fornecimento de materiais
  9. Controle PID da Garra do Robô em Matlab / Simulink
  10. Controle de qualidade da linha de embalagem automatizada