Pessoal,

Estou construindo encoder´s IR para medição de rotação de dois micro-motoredutores de um robô de duas rodas.
Estou a meses me debatendo com interrupções indevidas geradas no Arduino.

O projeto:

A leitura é feita nas rodas, através de codewheel impresso em laser.
Estou utilizando o TCRT5000 (pack reflexivo) para os sensores. Com eles consigo um sinal senoidal bastante boa, quase perfeita, oscilando aproximadamente entre 0,4 e 3,9 volts. A frequência é baixa (1 a 20 Hz).

O sinal gerado pelo Receptor do TCRT passa por um Schmitt Trigger (74HC14) e a onda quadrada gerada vai para o pino do Arduino.

O problema é na leitura do tempo entre pulsos no Arduino.

Utilizando "pooling" (lógica no loop()) não ocorrem problemas e consigo obter a leitura necessária, embora a técnica deixe a desejar em performance geral do robô.

Utilizando interrupção Externa ocorre detecção de interrupções indevidas. Utilizando interrupção Pin Change, a quantidade é menor, mas também ocorrem.

Porque interrupções Indevidas ?

Bem, com esse problema eu acabei comprando um Osciloscópio USB (20 MHz) e consigo com ele detectar que nos
momentos em que não há transição de estado no pino do Arduino ocorre interrupção mesmo assim, às vezes duas em um meio período do sinal.

Já utilizei várias técnicas para delimitar esse problema, sendo a mais simples e direta (na minha opinião) a seguinte:


. Na rotina de interrupção (ISR) eu apenas inverto a condição de uma variável booleana.
. No loop() eu analiso esta variável e aciono ou não uma saída digital do Arduino descarregando ao GND através de um resistor de 10k. Leio a forma de onda deste pino com o osciloscópio.

Assim consigo comparar o sinal gerado pelo TCRT, na saída do 74HC14, na entrada do pino de interrupção do Arduino e nesta saída digital que representa a informação houve ou não interrupção.

Só ocorre problema detectável - por esse osciloscópio - nesta saída digital! Todos os demais sinais estão conforme esperado.

Já utilizei direto no robô e em protoboard, Arduinos Uno, Nano e Mega. Todos apresentam o mesmo problema.
Já utilizei sensores IR como o TCRT, bem como TIL´s e uma Chave (de interrupção do feixe).
Já utilizei cabo blindado entre a placa de IR e o Arduino, com capacitor de 100nF e até 1uF descarregando o sinal no GND e nada. No caso do uso de capacitores, ocorre um pequeno arredondamento da forma de onda, mas continua sendo detectado normalmente pelo Arduino.

Considerando que o problema seja de algum transiente gerado no circuito - preciso girar um motor acionado por PWM para que o sensor IR possa gerar o sinal necessário - pergunto o que mais poderia fazer para tentar resolver esse drama ?

No motor estou utilizando capacitores de 100nF na sua alimentação, de cada fase da alimentação para GND e de sua carcaça para GND. Estou utilizando pinos para o PWM em 1KHz para frente e 500 para trás. Não há mudança do problema com isso.


Não sei se ficou claro a explicação. Para quem leu até aqui me desculpe a extensão do texto. O fato é que já procurei na internet inteira e não encontro ninguém relatando problema semelhante, pelo menos com uma "solução" para tentativa. A única informação boa que encontrei, mas mesmo assim apenas uma afirmação, é de que as interrupções do Arduino são "muito sensíveis".

Vejo em materias e vídeos na internet que inúmeras pessoas utilizam essa tecnica com aparente sucesso, portanto seria essa sensibilidade tão elevada assim ?

Já ia me esquecendo, mas dos meses em que me debato com isso, me preocupei muito com um provável transitente gerado no receptor do TCRT. Fiz inúmeros experimentos travando uma condição anormal, se existisse, e concluí que esta ppossibilidade esta descartada, pelo menos na bancada.

É problema de ruído ou pode ser alguma outra coisa ?

Idéias são muito bem vindas,

Obrigado,

Wilmar

Exibições: 8029

Anexos

Responder esta

Respostas a este tópico

Wilmar, por coincidência no momento estou estudando interrupções no Arduino.

Estou querendo usar interrupçóes para detectar a o acionamento de sesnores sem fio ou do controle remoto no projeto do Alarme  Arduino sem fio :

http://labdegaragem.com/forum/topics/projeto-alarme-sem-fio-arduino...

Vi no daatsheet do ATmega 328 (Arduino) que ele pode usar 26 tipos de interrupção.

Será que outro tipo de interrupção esta interferindo no tratamento da sua interrupção?

Sugiro verificar o status dos registradores de interrupção para descobrir se somente a sua interrupção esta operando.

Obrigado José Gustavo.

Já verifiquei se existem outras interrupções habilitas e não há nenhuma outra.

No projetinho do robô, eu uso I2C para comunicação entre um UNO R3 (master) e um Nano (motores), além de um magnetômetro e alguns PCF8574 para LCD e I/O adicional, porém nos testes que relato tudo isso está desligado, e eu sinceramente ainda não encontrei uma saída "limpa" para problemas de conflito entre as interrupções externas (dois motores / dois encoder´s) ou pin change e a comunicação I2C, porém como empaquei nos encoder´s...

Sugiro vc conseguir uma onda quadrada bem limpa qualquer, por ex de um oscilador 555 e ver se com ela da a mesma coisa. Aih vc isola o problema (Arduino ou sensor).

Ainda, sensores do tipo encoder costumam ler 2 pinos. Um é o clock e o outro direçao. Mas se vc simplesmente ler clock e direção quando o motor para exatamente sobre a transição e treme provoca falsos clocks.

A solução eletronica é usar um 74LS74, no modo SR (set e reset). De forma que se acontecer um clock ele seta e só reseta se acontecer um direção.

Nao sei se fui claro, mas isso impede que seja feita uma falsa leitura na base do vai-vem.

Como vc tem um microcontrolador no processo fica mais facil, pode implementar na programaçao. Seria um flag que indica que houve pulso direção. Setado por dir e resetado por clock, por ex.

Aih vc so considera o clock se o flag estiver setado, ou seja: uma vez. evitando a falsa leitura.

Se o seu sensor deteta só em uma direção (1 pino) esqueça essa segunda parte...

Obrigado Eduardo.

Eu esqueci de relatar no texto que os encoder´s são simples, sem direção. Optei assim porque pela lógica do programa (vários subprogramas interligados em um "master", para seguidor de linha, PING, etc...) eu sempre sei se os motores estão para frente ou em ré.

Quanto a idéia do 555 eu também já testei com ele mesmo. Na verdade, usando comparador de tensão ou schmitt trigger eu posso dizer que sempre obtive um sinal quadrado limpo, isso considerando que o "osciloscópio" é meia-boca. Mesmo utilizando o sinal senoidal do receptor do TCRT direto no Arduino os resultados são satisfatórios, além é claro das interrupções indevidas. Com isso concluí que o problema está do lado do Arduino mesmo. 

Já cheguei até a duvidar da capacidade do ATmega 328P de tratar adequadamente essas interrupções, mas lendo que alguns conseguem ler até quase megahertz se não me falha a memória, eu com uma faixa de 1 a 20Hz parece piada não conseguir.

OBS: Coloquei duas fotos no texto inicial para ilustrar a aplicação.

Entao nao sei...

Mas tentaria começar um novo programa do zero que apenas conte as interrupçoes e por ex mande o resultado pela serial. De 1 pino. E veja se funciona. Caso sim inclua o segundo pino, etc. Pq ele certamente faz isso corretamente. Tem algum detalhe errado aih, mas não tenho ideia.

Sim, também já comecei do zero inúmeras vezes, hehe. Aliás essa é uma excelente técnica e uma excelente dica, juntamente com aquela de você ir fazer outra coisa por uns tempos...

A forma de monitorar o que relato no texto é um sketch bem simples, com mais linhas para controle do PWM do motor do que para o encoder!. Ele está nos anexos desta resposta.

Eu já cheguei a utilizar um Arduino para fazer o PWM do motor e outro apenas para monitorar e processar a interrupção (externa ou pin change), com os Arduinos e circuitos respectivos acionados por diferentes fontes / baterias (com o GND conectado). Também apresenta interrupções indevidas.

Eu anexei dois print screen do "osciloscópio" (pela restrição a três anexos na resposta).

No primeiro, você tem o sinal do receptor do TCRT5000 e a saida do comparador de tensão (LM339) com alguma histerese. Eu cheguei a setar quase 3 volts de histerese, tentando "barrar" um transiente entre os cortes do LM!. 

Daí na segunda, temos o sinal de saída do LM para o Arduino (parece bom né) e o "pino da interrupção". Veja a m... Ocorre "interrupção" quando não há variação na entrada do pino do Arduino e às vezes ocorre perda de interrupção!!!.

OBS: As fotos que catei agora não são muito relacionadas, mas considere que isso ocorre em qualquer combinação de montagem, diferentes pinos testados, e muitos sketchs com diferentes lógicas...

Anexos

Wilmar ainda não estudei a sua rotina, 

Mas acabei de fazer um teste com uma rotina de Interrupção desse tutorial:

http://labdegaragem.com/profiles/blogs/tutorial-sobre-interrup-es-n...

Veja que o teste que eu fiz ficou muito instavel. Após introduzir um delay de 50 micro-segundos entre as alterações de estado ficou perfeito ! Totalmente estável.

No meu caso, os ruidos no acionamento do botão provocaram essa instabilidade.

Usei esse delay como debounce.

Já testei esse sketch do LdG com capacitor 100nF (meio exagerado inclusive) e não ocorreu problemas com interrupção indevida, porém como ficou meio lento o chaveamento nem precisei colocar delay.

Isso reforça "minhas conclusões" de que o PWM acionnando os motores (nos testes uso apenas um mas continua com o problema) é a fonte da interferência na interrupção.

No entanto, já fiz tudo "que sei" para tentar abrandar o PWM. Como relato, cheguei a utilizar capacitor poliéster de 1uF entre os contatos de alimentação do motor. O sinal de alimentação chega a arredondar nos vértices da onda quadrada e nada...

No extremo cheguei a alimentar diferentes Arduinos e seus circuitos - um com o PWM / potenciômetro de variação da rotação do motor / Led e outro com o Sensor IR e a interrupção de diferentes maneiras, o PWM com uma fonte 12V e o outro com bateria LIPO 3S e 7805 com trocentos capacitores de filtro / desacoplamento e também acontece as benditas interrupções indevidas.

Foram nestes momentos que comecei a pirar... Daí partí para tentar utilizat conversor de frequência para tensão (LM2907N - o único que achei aqui em Curitiba). Na pressa não compreendi bem o datasheet é só depois de montar uma plaquinha é que constatei que o bendito só funciona com sinal alternado!. Não achei outro que funcionasse bem com senoidal ou quadrada não alternada (IR / Schmitt).

Daí fico pensando, será que o bendito ATmega do UNO, Nano ou Mega funciona direito para isso ? Mas os vídeos comprovam que aparentemente sim!!.

Então, o que poderia ser ?? hehe

Fiz besteira nos anexos.

Então aproveito para aqui colocar mais dois print screen´s:

No primeiro, temos o sinal do receptor e a "saída da interrupção" mostrando as interrupções indevidas, que são confirmadas na segunda, onde é mostrada saida do LM / entrada do Arduino e a "saída de interrupção".

Lembre-se de que estes print screen não são de uma mesma situação, no entanto o problema ocorre da mesma forma. D7 no caso refere-se à saída digital 7 utilizada como "saída de interrupção".

Anexos

Cara é problema de debounce! 

Acrecente um delay  e deverá funcionar.

Faça testes - sugiro começar com 50 micro-segundos.

http://www.all-electric.com/schematic/debounce.htm

Já tentou mudar os modos de interrupção?

mode:

defines when the interrupt should be triggered. Four contstants are predefined as valid values:

  • LOW to trigger the interrupt whenever the pin is low,
  • CHANGE to trigger the interrupt whenever the pin changes value
  • RISING to trigger when the pin goes from low to high,
  • FALLING for when the pin goes from high to low.

The Due board allows also:

  • HIGH to trigger the interrupt whenever the pin is high.
(Arduino Due only)

José Gustavo,

Concordo.

Admitindo que as interrupções indevidas sejam por ruído um bom debounce deveria resolver a questão. No entanto, já testei o encoder condicionando o sinal com um schmitt trigger (74HC14 - o mesmo recomendado no artigo de seu link, que aliás já havia achado, juntamente com outros tantos). Daí então evoluí para o seguinte: se o sinal está sainda limpo do schmitt e chegando sujo no Arduino, então é no cabo que está sendo acrescentado o ruído, certo ?

Embora o meu osciloscópio meia-boca não permita uma conclusão definitiva, mesmo medindo o sinal direto no pino do Arduino!.

Agora, considerando que o cabo de aproximadamente 8 cm esteja servindo de antena, o que poderia fazer além de utilizar cabo blindado (desses de conexão de aparelhos de som) e um filtro no sinal através de um capacitorzinho ?

Aliás nesse ponto tenho uma dúvida que esquecí de mencionar até aqui: Eu coloquei uma tonelada de capacitores de 100nF para filtro / desacoplamento em todo o hardware do robô (várias placas que eu fabriquei, inclusive a ponte H para 4A), com exagero na quantidade inclusive. Porém em alguns lugares eu utilizei de poliéster ao invés de cerâmico que tendem a "quebrar" nas pernas. Seria o uso de cerâmicos tão imprescindível como recomenda a literatura ou poliéster dá conta do recado ??

A idéia do delay também já testei, verificando que o mesmo tem de ser "brutal" em função do período do sinal e neste caso como seriam dois encoder´s / interrupções acabariam prejudicando-se mutuamente..

Paralelamente, eu cheguei a utilizar uma histerese cavalar quando usando um comparador de tensão, com o mesmo propósito de mascarar uma eventual spike.

Mas como a ideía pode resolver, vou repensar um pouco.

Existe uma discussão longa no fórum do Arduino.cc sobre esse tema, onde o iniciador parecia estar ficando meio louco (como eu), e onde peguei várias aspectos interessantes. Infelizmente a discussão não chegou a uma solução, pelo menos no fórum.

Grato,

Wilmar

Sim, já testei todas elas.

No modo Change, aparentemente os problemas aumentam no caso de interrupção externa. Como na Pin Change essa questão é resolvida por software me pareceu indiferente, mas é meio no sentimento isso.

Eu também testei, no caso da Pin Change, em diferentes pinos, digitais, analógicos e nada.

RSS

© 2024   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço