Escolar Documentos
Profissional Documentos
Cultura Documentos
br
• Introdução
O controle PI ou PID são utilizados para monitorar e controlar saída de um sistema comparando esta com sua
entrada, definindo o erro e deste erro calculando PI ou PID para controlar o nível de correção e a velocidade de
correção para que a saída se aproxime o máximos do valor definido na entrada.
O objetivo desse trabalho foi desenvolver em C++ um software supervisório é de simular este controle e
gerenciar as informações que deve enviar ao Arduino e interpretar as informações recebidas dele, o software
desenvolvido possibilita que o usuário defina o valor de RPM desejado, sistema é convertido este valor para uma
valor entra 0 e 255, valor esse necessário para a saída PWM do Arduino, após receber esta informação o Arduino
transfere esse valor para saída PWM, pino 9 o qual esta conectado ao base do TIP122 controlando o fluxo de
corrente do mesmo para controle do motor que esta conectado ao coletor do TIP e o emissor conectado ao terra,
enquanto os led’d infravermelho efetuam a contagem de RPM (Saída) gerador por esse motor, enviando esta
informação para ser tratada no software e comparada com o SetPoint (Entrada) e desta diferença definindo o erro do
sistema, erro este que será utilizado com os valores definidos pelo usuário de KP e KI para definir a correção do
valor a ser enviado novamente para o Arduino, após o calculo de PI ele acresenta ou diminui este valor do antigo
valor de entrada para o sistema fazer a correção de RPM.
O programa desenvolvido consiste em uma tela principal, onde o usuário pode conectar a porta Com3, neste
momento esta habilitado a enviar valores para o SetPoint,nesta tela temos também botões para salvar e abrir
arquivos, um espaço para editar informações e visualizar os valores de RPM encontrados durante o ultimo ensaio,
também temos um gráfico que mostra duas linhas que representão SetPont e valor real de RPM e uma tela acima que
pode ser visualida qual foram os valores de KP e KI definidos na segunda tela.
Na segunda tela temos opições para alterar os valores de KP e KI que já vêm predefinidos que são 1,0 para KP e
0,0 para KI, nesta tela será possível vusializar dois campos que são onde devem escraver os valor desejados e no
final temois um botão escrito SetPoint que envia estes valores para a formula de PI e também fecha a tela.
Descrição das Classes
Para o software em desenvolvimento nesse trabalho, são criadas quatro classes: “TForm1”, “TForm2”, “TPID”,
“TComPort”. A primeira e a segunda são referente as telas do programa, a terceira se refere a classe TPID emde é
realizado os cálculos de controle do Software e a ultima se refere a parte do programa da comunicação entre PC e
hardware, esta foi criada com auxilio de um item da biblioteca do Builder C++, denominada de ComPort1.
• Classe “TForm1”
A classe “TForm1”, derivada da classe “TForm” da VCL, é a classe que gera a tela inicial “Principal” do
programa. A próxima figura mostra a representação visual UML dessa classe. Os códigos de programa, “Unit1.h” e
“Unit1.cpp” relacionados a essa classe, estão listados nos apêndices II e III respectivamente.
TPID prop;
int SetPoint;
static double memoria[1000];
static int C = 0;
float ValorPWM,ST, RPM;
int RPMpassada;
int RPMatual;
float kP = 1.0;
float kI = 0;
float kD = 0;
float erro, ResultadoPID, PID;
FILE * arq;
int compare = 0;
float RPMatualvezes;
float RPMatualdividido;
float RPManterior;
• TPID prop – método utilizado para chamar a classe para calculo de PID;
• memoria[1000] – ponteiro para 1000 valores de RPM recolhidos;
• ValorPWM – valor de SetPoint transformadp para valor que o arduino ronheceria de 0 a 255;
• C – para contar posição onde deve ser alocado valor de RPM na memoria[1000];
• * arq – ponteiro para o arquivo *.txt para carregar e salvar os dados de RPM lidos diretamente do
• kP, kI, kD – setado valores de paremetros para o calculo de PID;
• TForm1::Button3Click– O usuário digita um valor de Set Point e clica, o programa testa se o valor está entre os
limites pre definidos, se não apresenta uma mensagem de erro mostrando os limites corretos e se sim, faz um
calculo para transformar o Set Point em valor PWM e joga esse valor para o loop do timer;
•
•
•
•
•
•
•
•
•
•
•
•
•
•
• Fig. 6 – Fluxograma da rotina “Calculo PID”
• Calculo PID – Após o usuário digitar o valor de Set Point e ser testado como valido esse valor é transferido para
rotina timer, la antes de inicir o calculo temos um variável chamada de compare que tem como função limitar
o numero de valores transferidos para PWM, devido a resposta lenta do hardware não pode ser enviado um
valor para PWM a cada ciclo do timer, pois a velocidade ainda não sofreu a alteração do ultimo valor enviado
o que faz com que o sistema fique muito instável, atingindo zero de RPM e depois o máximo sem nunca
estabilizar, esta variável compare faz com o sistema envie uma informação fique recebendo o feedback no
mesmo ciclo mas só volte a calcular erro, PID e enviar os dados depois de 10 ciclos do timer, tempo
suficiente para o motor estabilizar, esta foi uma solução muito importante para estabilizar todo o sistema.
• A cada comparação que o valor de compare é igual a 10 o controle realiza o calculo de erro que é a diferença
entre o Set Point e o valor de RPM atual, este erro é setado na variável e enviado para classe PID onde é
calculado o ganho necessário para o sistema com base nos valores de Kp e Ki digitados pelo usuário ou caso
o usuário não os defina são utilizado os valor pre estabelecidos que são kP = 1,0 e kI = 0,0 este valores podem
ser alterados a qualquer momento durante a execução do programa.
• Com o calculo realizado a classe devolve o valor denominado PID para rotina principal onde este valor é
somado levando em consideração o sinal ao valor de PWM já existente e jogando novamente na variável
ValorPWM esta informação é enviada pela porta Com3 para o Arduino onde é colocado este valor no pino 9
que está conectado ao transistor que controla a corrente do motor
•
•Fig. 7 – Fluxograma do evento “TForm2::Button1Click”
• Classe “TForm2”
A classe “TForm2”, derivada da classe “TForm” da VCL, é a classe que gera a tela de inserção dos valores de kP
e kI “Valores” do programa. A próxima figura mostra a representação visual UML dessa classe. Os códigos de
programa, “Unit2.h” e “Unit2.cpp” relacionados a essa classe, estão listados nos apêndices IV e V respectivamente.
Quando clicado na tela Principal o botão conectar abre esta janela chamada de Setup, para configurar a comunicação serial, deve-se
verificar a porta que esta conectada e e velocidade de comunicação que foi setada na lógica do Arduino, pois se ela for diferente não comunicará
corretamente.
A segunda tela chamada valores que chamada na tela principal na aba SetPoint, tem os campos para escrever os valor de kP e kI e o
botão de SetPoint que envia estes valores para lógica.
Na tela Principal temos o espaço para o usuário escrever o SetPoint, caso escreva ul valor fora dos limitas especificado no projeto e
clicar no enviar aparecerá uma janela de aviso que o valor esta incorreto e quais são os limites
Na tela principal o usuário também tem a opção de alterar a cor do painel principal, somente necessário clicar em algum ponto da tela
que vai abrir a janela de seleção de cores onde somente necessário selecionar na cor desejada e clicar em ok.
• Arquivos de Dados
O software em estudo salva dados em dois tipos de arquivo: *.txt.
No primeiro tipo de arquivo, do tipo *.txt, é gerado apenas um arquivo “arquivo” onde são salvos os dados dos
últimos ensaio realizado com o numero da amostra e o valor de RPM lido.
• Lista de Apêndices
• I – Descrição do Hardware;
• II – Listagem do Código “Unit1.h”;
• III – Listagem do Código “Unit1.cpp”;
• IV – Listagem do Código “Unit2.h”;
• V – Listagem do Código “Unit2.cpp”;
• VI – Listagem do Código “TPID.h”;
• Considerações Finais e Conclusões
O presente trabalho foi um software supervisório para controle de RPM do motor com Arduino Mega, apresentou
facilidade na comunicação serial com um item da própria biblioteca, facilitando a configuração pois foi somente
incluir este item e fazer com que o botão chamado “conectar” ativa-se “ComPort1->Open();” abrira uma janela que só
é necessário definir a velocidade de comunicação e pronto.
Para o controle propriamente dito ouve dificuldade no momento da leitura dos valor pois o software estava lendo
em alguns casos mais ou até menos dígitos do que o valor real o alterava consideravelmente o resultado do calculo de
erro, acredito que o problema esta na velocidade de leitura em relação a velocidade de escrita do Arduino Mega na
porta Com3.
Uma melhoria que se tentou foi uma espécie de filtro para valores muito alto e valores muito baixos, mas não foi
implementado com sucesso, acrito que a implementação de forma adquada deste filtro traria um resultado muito bom
para o funcionamento do sistema como um todo.
Referências
1. Luis Fernando Espinosa Cocian, Engenharia de Processamento Digital II, Canoas: Ed. ULBRA, 2008, 276 p.
2. Luis Fernando Espinosa Cocian, Manual da Liguagem C, 1ª ed., Canoas: Ed. ULBRA, 2004, 500 p.
3. “C++ COMO UMA LINGUAGEM DE PROGRAMAÇÃO ORIENTADA A OBJETOS.” André Augusto Cesta.
4. Orientadora: Profa Dra Cecília Mary Fischer Rubira
5. Site: http://www.arduino.cc/en/reference/serial
6. Site: https://www.youtube.com/watch?v=BZZbGa9NXwo
7.
Sobre o Autor
int TransistorPin = 9;
void setup()
{
Serial.begin(9600);
Serial.flush();
pinMode(TransistorPin, OUTPUT);
pinMode (sensor , INPUT);
}
void loop()
{
if (Serial.available() > 0) {
int index=0;
delay(100); // let the buffer fill up
int numChar = Serial.available();
if (numChar>15) {
numChar=15;
}
while (numChar--) {
buffer[index++] = Serial.read();
}
splitString(buffer);
}
rpmconta = 0; //Zera a variável que armazena a contagem de rotações
attachInterrupt(0, pegarpm, FALLING); //Habilita o pino 2(INT 0) para atender a
interrupção (pegarpm) por borda de descida (FALLING).
delay(250); //Aguarda 0,25 segundo
detachInterrupt(0); //Desabilita a interrupção
rpmconta = rpmconta * 8; //Multiplica a contagem por 8 para pegar o RPM
Serial.print(rpmconta, 5); //Imprime o valor de RPM na serial
}
void pegarpm()
{
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include <stdio.h>
#include <time.h>
#include "TPID.h"
#include "Unit1.h"
#include <string>
#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "CPort"
#pragma resource "*.dfm"
TForm1 *Form1;
TPID prop;
int SetPoint;
static double memoria[1000];
static int C = 0;
float ValorPWM,ST, RPM;
int RPMpassada;
int RPMatual;
float kP = 1.0;
float kI = 0;
float kD = 0;
float erro, ResultadoPID, PID;
FILE * arq;
int compare = 0;
float RPMatualvezes, RPMatualdividido ,RPManterior;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Memo1->Lines->Clear();
Memo2->Lines->Clear();
Memo3->Lines->Clear();
}
//---------------------------------------------------------------------------
}
//-------------------------------------------------------------------------
if (C > 1000){
C = 0;
}
C++;
ComPort1->WriteStr(ValorPWM);
AnsiString tempo;
kP = StrToFloat(Label1->Caption);
kI = StrToFloat(Label2->Caption);
clock_t start, end;
start = clock();
float acumulador;
AnsiString x;
static float Tempo;
ComPort1->ReadStr(x,5);
RPMatual = x.ToDouble();
if (compare == 10){
compare = 0;
erro = SetPoint - RPMatual;
//P
prop.constante2(kI);
prop.constante4(Tempo);
prop.constante1(kP);
prop.calculo1(erro);
ResultadoPID = prop.resultado1();
PID = ResultadoPID;
PID = 0;
if (ValorPWM < 0){
ValorPWM = 0;
}
}
compare++;
ComPort1->WriteStr(ValorPWM);
memoria[C] = ValorPWM;
static int i = 0;
i++;
fprintf(arq, "%d\t%d\n", i, RPMatual);
Series1->AddXY(i, RPMatual, "", clTeeColor);
Series2->AddXY(i, Edit2->Text.ToDouble(), "", clTeeColor);
end = clock();
Tempo = 350 + end - start;
Memo2->Lines->Add(Tempo);
}
//---------------------------------------------------------------------------
SetPoint=StrToFloat(Edit1->Text);
//---------------------------------------------------------------------------
#ifndef Unit2H
#define Unit2H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Chart.hpp>
#include <ExtCtrls.hpp>
#include <Series.hpp>
#include <TeEngine.hpp>
#include <TeeProcs.hpp>
#include "CPort.hpp"
//---------------------------------------------------------------------------
class TForm2 : public TForm
{
__published: // IDE-managed Components
TButton *Button1;
TEdit *Edit1;
TEdit *Edit2;
TLabel *Label1;
TLabel *Label2;
void __fastcall Button1Click(TObject *Sender);
void __fastcall Timer1Timer(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TForm2(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm2 *Form2;
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#include "Unit2.h"
#include "TPID.h"
#include <string>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "CPort"
#pragma resource "*.dfm"
TForm2 *Form2;
float kP, kI, kD;
//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
•
•
class TPID {
private:
float P, error,I,D, kProp, kInt, kDer,PID,temp;
float AScaracteristica;
public:
void constante1 (float kP);
void constante2 (float kI);
void constante3 (float kD);
void constante4 (float Tempo);
float resultado1 (void);
void calculo1 (float e);
};