Preciso criar uma rotina via software para ajuste automático de rpm medidos por um sensor óptico para comandar um motor via pino pwm do arduino mega 2560. Preciso que o programa pegue um rpm digitado pelo operador (ex: 3000) e o ardunio monitore e deixe esse rpm dentro de uma porcentagem de erro aceitável como 2% por exemplo. Preciso fazer chegar a 3000 e dai reajustar pra menos se passar de 3060 e pra mais se baixar de 2940. Esta assim por enquanto. 

#include <ctype.h>
#include <string.h>
#include <Button.h>
#include <Keypad.h>
#include <LiquidCrystal.h>

#define rs 6
#define en 7
#define d4 8
#define d5 9
#define d6 10
#define d7 11

LiquidCrystal lcd = LiquidCrystal(6,7,8,9,10,11);

#define pinoSensor 2
#define btCima 22
#define btBaixo 23
#define btSeta 24
#define btReseta 25

#define ledVd 29
#define ledVm 28
#define ledAm 30
#define ledAz 31

#define sA 44
#define sB 45
#define velMotor 46

#define linha1 A0
#define linha2 A1
#define linha3 A2
#define linha4 A3
#define coluna1 A4
#define coluna2 A5
#define coluna3 A6
#define coluna4 A7

const byte nL=4;
const byte nC=4;
byte pinL[nL]={linha1, linha2, linha3, linha4};
byte pinC[nC]={coluna1, coluna2, coluna3, coluna4};
char teclas[nL][nC]=
{
{'1','2','3','A'},

{'4','5','6','B'},

{'7','8','9','C'},

{'*','0','#','D'}
};
Keypad teclado=Keypad(makeKeymap(teclas),pinL,pinC,nL,nC);

Button nav_Cima=Button(btCima, BUTTON_PULLUP_INTERNAL, true, 20);
Button nav_Baixo=Button(btBaixo, BUTTON_PULLUP_INTERNAL, true, 20);
Button nav_Seta=Button(btSeta, BUTTON_PULLUP_INTERNAL, true, 20);
Button nav_Reseta=Button(btReseta, BUTTON_PULLUP_INTERNAL, true, 20);

void mudaMenu();
void nMenus();

String msg0;
String msgA;
String msgB;
String msgC;
String msgD;
String msgE;

volatile unsigned long pulsos;
unsigned long marca;
unsigned int pulsos_por_volta = 8;
int rpm;

int menu=0;
bool atualizarMenu=true;
bool modoAuto=false;

bool leTeclado1=false;
bool leTeclado2=false;
bool leTeclado3=false;

bool permiteNavegar=true;
char valorVel[4]="___";
long valorV=-1;
char valorRpm[5]="____";
long valorR=-1;

float valorX1;
float valorX2;
float x1=1.02;
float x2=0.98;

bool sentido=true;
bool ligado=false;
byte vel=140;


void setup(){

msg0="Menu CCM";
msgA="1. Ligar motor";
msgB="2. Sentido B";
msgC="3. Setar vel.";
msgD="4. Rpm +/-";
msgE="5. Mdo. Auto.";

pinMode(pinoSensor, INPUT_PULLUP);
pinMode(velMotor,OUTPUT);
pinMode(sA, OUTPUT);
pinMode(sB, OUTPUT);
pinMode(ledVd, OUTPUT);
pinMode(ledVm, OUTPUT);
pinMode(ledAm, OUTPUT);
pinMode(ledAz, OUTPUT);

digitalWrite(sA, 1);
digitalWrite(sB, 0);
analogWrite(velMotor,0);
digitalWrite(ledVd,0);
digitalWrite(ledVm,1);
digitalWrite(ledAm,1);
digitalWrite(ledAz,0);



attachInterrupt(digitalPinToInterrupt(pinoSensor),contaPulsos,RISING);
lcd.begin(16,2);
Serial.begin(115200);

pulsos=0;
rpm=0;
}

void loop(){

mudaMenu();
nMenus();



if ((millis()-marca)>1000) {
noInterrupts(); // desligo as interrupções
rpm=(60*1000/pulsos_por_volta)/(millis()-marca)*pulsos;

unsigned temp=pulsos;
pulsos=0;
interrupts();
if(leTeclado2){
lcd.setCursor(12,0);
lcd.print(rpm, DEC);
}
if(modoAuto){


if(valorR>valorX1){
vel++;
analogWrite(velMotor,vel);
}
if(valorR<rpm){
vel--;
analogWrite(velMotor,vel);
}
}
Serial.print("RPM = ");
Serial.println(rpm, DEC);
Serial.println(vel);
Serial.println(valorX1);
Serial.println(valorX2);
marca = millis();

}
}

void contaPulsos(){
pulsos++;
}

void mudaMenu(){

char lido=teclado.getKey();

if(leTeclado1){
if(lido!=0){
if(lido=='#'){
for(int i=0; i<strlen(valorVel); i++){
if(valorVel[i]=='_') valorVel[i]='0';
}
valorV=atoi(valorVel);
if(valorV>100){
valorV=-1;
strncpy(valorVel,"___",3);
lcd.setCursor(0,1);
lcd.print(valorVel);
}else{
strncpy(valorVel,"___",3);
permiteNavegar = true;
menu=2;
atualizarMenu=true;
leTeclado1=false;
vel=map(valorV, 0, 100, 0, 255);
analogWrite(velMotor,vel);
}
}else{
if(isdigit(lido)){
valorVel[0]=valorVel[1];
valorVel[1]=valorVel[2];
valorVel[2]=lido;
lcd.setCursor(0,1);
lcd.print(valorVel);
}
}

}
}
if(leTeclado2){
if(lido=='A'){

if(vel<255){
vel++;
analogWrite(velMotor,vel);
}
}

if(lido=='B'){

if(vel>0){
vel--;
analogWrite(velMotor,vel);
}
}
}

if(leTeclado3){
modoAuto=true;
if(lido!=0){
if(lido=='#'){
for(int i=0; i<strlen(valorRpm); i++){
if(valorRpm[i]=='_') valorRpm[i]='0';
}
valorR=atoi(valorRpm);
valorX1=rpm*x1;
valorX2=rpm*x2;
if(valorR>3500){
valorR=-1;
strncpy(valorRpm,"____",4);
lcd.setCursor(0,1);
lcd.print(valorRpm);
}else{
strncpy(valorRpm,"____",4);
permiteNavegar = true;
menu=4;
atualizarMenu=true;
leTeclado3=false;
}
}else{
if(isdigit(lido)){
valorRpm[0]=valorRpm[1];
valorRpm[1]=valorRpm[2];
valorRpm[2]=valorRpm[3];
valorRpm[3]=lido;
lcd.setCursor(0,1);
lcd.print(valorRpm);
}
}

}
}

bool cima=nav_Cima.uniquePress();
bool baixo=nav_Baixo.uniquePress();
bool seta=nav_Seta.uniquePress();
bool reseta=nav_Reseta.uniquePress();

if(cima){
if(permiteNavegar){
atualizarMenu=true;
menu++;
if(menu>4)menu=0;
}
}
if(baixo){
if(permiteNavegar){
atualizarMenu=true;
menu--;
if(menu<0)menu=4;
}
}
if(seta){
switch(menu){
case 0:
ligado=!ligado;
leTeclado1=false;
leTeclado2=false;
leTeclado3=false;
if(ligado){
analogWrite(velMotor,vel);
digitalWrite(ledVd,1);
digitalWrite(ledVm,0);
msgA="1.Desligar motor";
}
else{
analogWrite(velMotor,0);
digitalWrite(ledVd,0);
digitalWrite(ledVm,1);
msgA="1. Ligar motor";
}
atualizarMenu=true;
break;

case 1:
sentido=!sentido;
leTeclado1=false;
leTeclado2=false;
leTeclado3=false;
if(sentido){
digitalWrite(sA, 0);
digitalWrite(sB, 1);
digitalWrite(ledAm,0);
digitalWrite(ledAz,1);
msgB="B. Sentido A";
}else{
digitalWrite(sB, 0);
digitalWrite(sA, 1);
digitalWrite(ledAm,1);
digitalWrite(ledAz,0);
msgB="2. Sentido B";
}
atualizarMenu=true;
break;

case 2:
leTeclado1=true;
leTeclado2=false;
leTeclado3=false;
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Insira % vel:");
lcd.setCursor(0,1);
lcd.print(valorVel);
break;

case 3:
leTeclado2=true;
leTeclado1=false;
leTeclado3=false;
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Rpm medido=");
lcd.setCursor(12,0);
lcd.print(rpm, DEC);
lcd.setCursor(0,1);
lcd.print(" Tcl A+ Tcl B-");
break;

case 4:
leTeclado3=true;
leTeclado1=false;
leTeclado2=false;
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Insira o Rpm:");
lcd.setCursor(0,1);
lcd.print(valorRpm);
break;

}
}
}

void nMenus(){
switch(menu){

case 0:
if (atualizarMenu){
modoAuto=false;
leTeclado2=false;
lcd.clear();
lcd.setCursor(0,0);
lcd.print(msg0);
lcd.setCursor(0,1);
lcd.print(msgA);
atualizarMenu=false;
}
break;

case 1:
if (atualizarMenu){
modoAuto=false;
leTeclado2=false;
lcd.clear();
lcd.setCursor(0,0);
lcd.print(msg0);
lcd.setCursor(0,1);
lcd.print(msgB);
atualizarMenu=false;
}
break;

case 2:
if (atualizarMenu){
modoAuto=false;
leTeclado2=false;
lcd.clear();
lcd.setCursor(0,0);
lcd.print(msg0);
lcd.setCursor(0,1);
lcd.print(msgC);
atualizarMenu=false;
}
break;

case 3:
if (atualizarMenu){
modoAuto=false;
leTeclado2=false;
lcd.clear();
lcd.setCursor(0,0);
lcd.print(msg0);
lcd.setCursor(0,1);
lcd.print(msgD);
atualizarMenu=false;
}
break;

case 4:
if (atualizarMenu){
leTeclado2=false;
lcd.clear();
lcd.setCursor(0,0);
lcd.print(msg0);
lcd.setCursor(0,1);
lcd.print(msgE);
atualizarMenu=false;
}
break;
}
}

Exibições: 127

Anexos

Responder esta

Respostas a este tópico

Boa noite TBF, (se não gosta que te chame pelas iniciais, avise),

por favor, já que postou o arquivo com o seu sketch, remova o que está na área de texto do seu tópico.

Além de dificultar navegar no seu tópico, ele pode perder caracteres de programação e perde a iindentição.

Leia :  http://labdegaragem.com/forum/topics/sugest-o-de-como-postar

PS:  Vi que também postou no fórum arduino: 

https://forum.arduino.cc/t/rotina-de-auto-ajuste/903348

RV mineirin

olá Thiago.

      Recentemente publiquei em um tópico aqui no LDG,  uma técnica para medição de RPM  com alta precisão.  Os resultados são bastante impressionantes, como vc pode ver no vídeo a seguir:

      E o tópico correspondente, vc pode ver neste link:  "RPM com precisão"

      Também analisei todo seu código, e embora a técnica que vc esteja usando para medir a RPM tenha uma precisão muito limitada,  há pontos muito positivos no código que vc postou aqui (arquivo "trabalho_Motor.ino").  Um desses pontos positivos, que é muito raro de se ver aqui no LDG, é que vc não usou "delay"  em nenhum ponto do seu código (então sobre isso tenho que te dar os parabéns).

      Mas há também alguns pontos que precisam ser bastante melhorados no seu código.  Um deles é que ele está um pouco "bagunçado" e algumas funcionalidades estão ligeiramente misturadas.  Um problema com isso,  é que conforme seu código evolui, vai ficando cada vez mais difícil de trabalhar com ele, e com isso aumenta a possibilidade de aparecerem Bugs (inclusive daqueles "brabos", que acabam se tornando difíceis de resolver, e quando se resolve tem o efeito colateral de criar novos Bugs).

      Uma coisa que percebi,  é que vc tentou criar uma Máquina de Estados  (não sei se isso foi intencional ou não),  mas infelizmente a técnica que vc usou é inadequada. Veja: Máquinas de Estado  são extremamente confiáveis, e muito simples de se implementar,  mas para isso é preciso que se use a técnica adequada.

      Por isso tomei a liberdade de fazer a implementação desse seu código usando tais técnicas. Irei testar para confirmar o funcionamento, e então publicarei aqui no seu tópico.

      Aproveito para pedir a vc, que atenda a solicitação do nosso querido RV - Rui Viana (na minha opinião, ele é a maior preciosidade daqui do LDG),  removendo o código que vc postou na área de texto, pelos motivos que o RV já descreveu.

      abrçs,

      Elcids

olá novamente Thiago.

      Em uma análise mais cuidadosa no seu código,  percebi que a forma como ele funciona,  está bastante familiarizada para vc. E caso eu alterasse drasticamente isso,  poderia provocar uma dificuldade, já que teria que gastar tempo analisando o funcionamento, além de existir a possiblidade dificultar para vc executar novas alterações.

      Por este motivo  irei publicar dois códigos,  um mantendo a exata lógica que vc está usando,  e outro com técnicas mais clássicas e adequadas (sem aqueles "inconvenientes" que mencionei anteriormente) e que vc poderá analisar quando quiser ou puder.  Mas em ambas as versões,  irei aplicar a técnica de medição da RPM usada no Sistema mostrado no vídeo da postagem anterior.

      Implementei uma Simulação do Sistema,  e o Hardware desta simulação segue os settings do seu código, conforme vc pode ver na figura a seguir:

(clique na figura para "zoom")

      A este hardware, irei acrescentar também um Driver do Motor,  mas apenas para efeito de "animação" da Simulação,  pois os modelos de Motores DC  existentes no Proteus não tem um mecanismo para acoplamento de um Sensor de Rotação.

      Assim para contornar esta limitação, e ter uma realimentação da rotação atual do Motor,  filtrei o PWM e usei a saída desse filtro como sinal de entrada de um VCO.  A faixa de tensão  e a faixa de frequência deste VCO,  foram ajustadas para serem realísticas em relação à resposta de um Sensor de Rotação  com taxa de 8 pulsos por giro do eixo do Motor (já que seu Sistema usa essa taxa).  Este mecanismo já está implementado na figura anterior (canto inferior direito, dentro do retângulo em verde), e já está funcionando corretamente.  Mas ainda irei acrescentar ali, um ajuste que emula uma variação da RPM,  de forma a induzir um desvio em relação ao PWM atual,  o que permitirá que se veja de forma mais clara (e didática),  o comportamento do "auto-ajuste"  da RPM que vc implementou.

      Mas apesar das ligações no Hardware da Simulação,  algumas dúvidas ficaram.  Por exemplo:  como não sei como vc ligou os LEDs no seu Sistema (se está acionando por "HIGH" ou por "LOW"),  também não sei quem está sinalizando o quê.  Assim poderia me informar a função de dois dos LEDs?   Especificamente:  o que o LED verde  indica, e o que o LED amarelo  indica ?  Ou então: os LEDs no seu Sistema são acionados por "HIGH" ou por "LOW"?

      Outra coisa:  assim que o Sistema é ligado,  e se navega pelo Menu através das teclas "Cima" ou "Baixo",  quando aparece a informação "2. Sentido B",  isto indica que inicialmente está no Sentido "B",  ou indica que está no "A" e pode ser alterada para "B"?

      Ah sim,  vc está usando um Driver de Motor integrado tipo "L298N",  ou vc implementou uma Ponte discreta  com Transistores?

      Agradeço sua atenção,

      abrçs,

      Elcids

RSS

© 2024   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço