segunda-feira, 22 de abril de 2013

Devagar...

Sim. Ando meio sumido...
Essa semana foi uma correria, tive pouco tempo para brincar com qualquer coisa, mas já estou com algumas idéias...

Agora com o modbus consolidado no conjunto arduino/scadabr, posso começar a desenvolver alguma maquete de automação,  essa semana tenho pensando em montar um modelo de Centro de distribuição de Água, que é basicamente constituído de um reservatório enterrado ou semi-enterrado que abastece um reservatório elevado através de um conjunto de recalque.

Pensei em pegar um motor desses utilizados em limpadores de para-brisas 12V e usar uma lógica de PWM para controlar sua velocidade os níveis tanto do REN como do REL vou controlar (e fazer o atumomatismo local da bomba) com uma ideia que encontrei meio que sem querer em um blog hoje, que consiste na construção de um sensor de proximidade utilizando leds IR. Dê uma olhada: http://www.vidiotsquad.com/category/ir-sensors/ . 

Lembro que esse tipo de adaptação cabe para distancias de até 300mm, como irei utilizar reservatórios pequenos, me atende. A medição será (a primeiro instante) feita com os sensores dentro de um tubo transparente juntamente com uma bolinha de isopor, funcionando como uma espécie de régua de nível digital... Pela lógica é só calcular os valores lidos no arduino e através de uma regra de 3, criar os fundos de escala e conversões dos valores para os níveis.

Com novidades, volto a postar. 

sexta-feira, 12 de abril de 2013

Finalmente

Agora acho que finalmente consegui manter a comunicação rodando constante sem perda de sinal quando atuo em equipamentos. Não tive tempo de estudar o código da biblioteca, mas ela tem me atendido muito bem.



Outra implementação interessante e quem tem funcionado bem, foi a gravação de dados na memória do Arduino (EEPROM), que ajuda no caso de reset do equipamento. 

Abaixo o código:



#include <modbus.h>
#include <modbusDevice.h>
#include <modbusRegBank.h>
#include <modbusSlave.h>
#include <EEPROM.h>

#include "DHT11.h" // Importa a Biblioteca do sensor de umidade e temperatura
#include <Servo.h>

modbusDevice regBank;
modbusSlave slave;


//variaveis de controle do sistema
int constMotorT = 0;
int ConstMotor = constMotorT;
int FimMotor = 1023;
int val = 0;
int Comando = 0;
int TempAtual = 0;
int TempSETPT = 0;

Servo myservo; // crie objeto Servo para controlar o motor de HD

int ledPin4 = 4;
#define dht11_pin 4 // Usa o pino digital 4 para receber umidade/temperatura
// Cria Instancia da Classe do sensor de temperatura
DHT11 sensor1(dht11_pin);


void setup()
{   

         myservo.attach(9); // setando o pino do servo 
        
        sensor1.Initialize(); //inicializando o sensor de temperatura e umidade
  
        regBank.setId(1);

/*
modbus registers follow the following format
00001-09999  Digital Outputs, A master device can read and write to these registers
10001-19999  Digital Inputs, A master device can only read the values from these registers
30001-39999  Analog Inputs, A master device can only read the values from these registers
40001-49999  Analog Outputs, A master device can read and write to these registers 

Analog values are 16 bit unsigned words stored with a range of 0-32767
Digital values are stored as bytes, a zero value is OFF and any nonzer value is ON

It is best to configure registers of like type into contiguous blocks.  this
allows for more efficient register lookup and and reduces the number of messages
required by the master to retrieve the data
*/

/* ************************** IMPORTANTE ************************************
   OS BLOCOS ABAIXO SÃO IMPORTANTES AO TRABALHARMOS COM OUTROS SCADAS COMO O ELIPSE SCADA
*/

/*Add Digital Output registers 00001-00016 to the register bank
  regBank.add(1);
  regBank.add(2);
  regBank.add(3);
  regBank.add(4);
  regBank.add(5);
  regBank.add(6);
  regBank.add(7);
  regBank.add(8);
  regBank.add(9);
  regBank.add(10);
  regBank.add(11);
  regBank.add(12);
  regBank.add(13);
  regBank.add(14);
  regBank.add(15);
  regBank.add(16);

//Add Digital Input registers 10001-10008 to the register bank
  regBank.add(10001);  
  regBank.add(10002);  
  regBank.add(10003);  
  regBank.add(10004);  
  regBank.add(10005);  
  regBank.add(10006);  
  regBank.add(10007);  
  regBank.add(10008);  

//Add Analog Input registers 30001-10010 to the register bank
  regBank.add(30001);  
  regBank.add(30002);  
  regBank.add(30003);  
  regBank.add(30004);  
  regBank.add(30005);  
  regBank.add(30006);  
  regBank.add(30007);  
  regBank.add(30008);  
  regBank.add(30009);  
  regBank.add(30010);  
*/
//Add Analog Output registers 40001-40020 to the register bank - No ScadaBr vou usar somente a faixa de registradores do holding, lembre-se que o ScadaBr tem faixa 0 de endereçamento
  regBank.add(40001);  
  regBank.add(40002);  
  regBank.add(40003);  
  regBank.add(40004);  
  regBank.add(40005);  
  regBank.add(40006);  
  regBank.add(40007);  
  regBank.add(40008);  
  regBank.add(40009);  
  regBank.add(40010);  
  regBank.add(40011);  
  regBank.add(40012);  
  regBank.add(40013);  
  regBank.add(40014);  
  regBank.add(40015);  
  regBank.add(40016);  
  regBank.add(40017);  
  regBank.add(40018);  
  regBank.add(40019);  
  regBank.add(40020);  

/*
Assign the modbus device object to the protocol handler
This is where the protocol handler will look to read and write
register data.  Currently, a modbus slave protocol handler may
only have one device assigned to it.
*/
  slave._device = &regBank;  

// Initialize the serial port for coms at 9600 baud  
  slave.setBaud(9600);   
}

long previousMillis = 0; // previousMillis irá armazenar o ultimo número da função millis()
long interval = 1000; // intervalo em que o motor irá esperar

void loop()
{

  //lendo a constante do motor salva na emprom - endereços 0 e 1 da Eprom
  //Essa foi a última implementação, interessante pois em caso de reset do equipamento eu posso recuperar a última leitura e assim não travo o processo
  byte hiByteT = EEPROM.read(0);
  byte lowByteT = EEPROM.read(0 +1);
  constMotorT  = word(hiByteT, lowByteT);
  ConstMotor = constMotorT;
  
  regBank.set(40004, (int) EEPROM.read(2)); //Set-Point
  regBank.set(40001, (int) EEPROM.read(3)); //umidade
  regBank.set(40002, (int) EEPROM.read(4)); //temperatura  
  

 while(1)
 {
    
  //************** SENSOR DE TEMPERATURA E UMIDADE ***********************
  double sensorData[2];
  int result;
  result = sensor1.Read(sensorData);                
  //*************** FIM DE SENSOR *****************************************  
          
 /*Escrevendo no ModBus = regBank.SET */
    regBank.set(40001, (int) 27 + sensorData[0]); //umidade
    regBank.set(40002, (int) sensorData[1]); //temperatura
    regBank.set(40003, (int) ConstMotor); //velocidade moto


 /*Lendo do ModBus = regBank.GET */
    int Comando = regBank.get(40004); //Lendo o valor do Set-Point da temperatura
    int TempAtual =  regBank.get(40002); //Lendo o valor da temperatura

//Na impossibilidade de usar o Delay(0 por truncar a execução do script, vamos partir para um millis().

    unsigned long currentMillis = millis(); //variável currentMillis irá armazenar o tempo
    if(currentMillis - previousMillis > interval) {
        previousMillis = currentMillis; //armazena a variável currentMillis para previousMillis
    
        //verifico a existencia de comando e solto as rotinas...
        if (Comando > 0){
              if (ConstMotor < FimMotor){ 
                if (Comando < TempAtual){ //se o set-point é menor que a temp atual eu acelero o motor
                  ConstMotor = ConstMotor + 10;  
                  val = map(ConstMotor, 0, 1023, 0, 179); 
                  myservo.write(val); 
                  regBank.set(40003, (int) ConstMotor);
                }  
              }

         if (Comando > TempAtual){ //se o set-point é maior que a temp atual eu reduzo o motor
             if (ConstMotor > 10) {
               ConstMotor = ConstMotor - 10;  
               val = map(ConstMotor, 0, 1023, 0, 179); 
               myservo.write(val); 
               regBank.set(40003, (int) ConstMotor);
             }else {
               ConstMotor = 0;  //se já for menor que 10 eu paro o motor de vez
               val = map(ConstMotor, 0, 1023, 0, 179); 
               myservo.write(val); 
               regBank.set(40003, (int) ConstMotor);                
             }
         }
        }
         if (Comando == 0){
            ConstMotor = 0;  
            val = map(ConstMotor, 0, 1023, 0, 179); 
            myservo.write(val); 
            regBank.set(40003, (int) ConstMotor);
          }
        //}  
    }
    
    //escrevendo na eprom
     EEPROM.write(2, regBank.get(40004));
     EEPROM.write(3, regBank.get(40001));
     EEPROM.write(4, regBank.get(40002));     
     
     byte hiByteT = highByte(ConstMotor);
     byte loByteT = lowByte(ConstMotor);
     EEPROM.write(0, hiByteT);
     EEPROM.write(1, loByteT);

    
     slave.run(); 
  }
}

terça-feira, 9 de abril de 2013

Mais alguns testes...

Agora com o modbus rodando mais estável...
Faltando algumas correções no tempo do motor (no inicio), serão corrigidas em breve...


Novamente, me desculpem pelo vídeo tosco, foi o que deu para fazer em horário de almoço...

A meta da semana além de montar uma bancada é implementar uma rotina para armazenar algumas informações no próprio arduino, sem a utilização de módulo SD. Como no projeto vou precisar de algumas variáveis retentivas que no caso de um reset do arduino (no papel de CLP) não sejam deletadas, para isso a biblioteca EEPROM.

Eis um ótimo post que explica sua utilização: http://labdegaragem.com/profiles/blogs/tutorial-usando-a-eeprom-do-arduino-para-armazenar-dados-de-forma


segunda-feira, 8 de abril de 2013

ModBus - primeiros resultados

Olá!

Depois de alguns dias batendo cabeça com libaries dos mais diversos tipos parece que consegui encontrar uma que atendeu minhas necessidades com certa estabilidade.

Estou fazendo os testes simulando a aceleração do motor visando o controle de temperatura e tudo tem rodado tranquilamente sem travamentos como estavam ocorrendo.

Um detalhe importante é a proibição da utilização do delay() dentro do loop quando rodando em modbus, depois de algumas horas e umas boas cervejas consegui adaptar a millis() em meu código.

Ma qual a necessidade de um delay no código? Simples, evitar a aceleração imediata do motor; basicamente ele acelera um pouco, espera 3 segundos, testa a temperatura desejada com a atual e acelera novamente até atingir seu limite de giros ou a temperatura desejada.

No decorrer da semana irei montar todos os componentes novamente e filmo o resultado.

Fonte da biblioteca ModBus utilizada: https://code.google.com/p/arduino-modbus-slave/

Código preliminar (vou transformar alguns pontos em funções):


#include <modbus.h>
#include <modbusDevice.h>
#include <modbusRegBank.h>
#include <modbusSlave.h>

#include "DHT11.h" // Importa a Biblioteca do sensor de umidade e temperatura
#include <Servo.h>

/*
This example code shows a quick and dirty way to get an
arduino to talk to a modbus master device with a
device ID of 1 at 9600 baud.
*/

//Setup the brewtrollers register bank
//All of the data accumulated will be stored here
modbusDevice regBank;
//Create the modbus slave protocol handler
modbusSlave slave;


//variaveis de controle do sistema
int ConstMotor = 0;
int FimMotor = 1023;
int val = 0;
int Comando = 0;
int TempAtual = 0;


Servo myservo; // crie objeto Servo para controlar o servomotor

int ledPin4 = 4;
#define dht11_pin 4 // Usa o pino digital 4 para receber umidade/temperatura
// Cria Instancia da Classe do sensor de temperatura
DHT11 sensor1(dht11_pin);


void setup()
{   

         myservo.attach(9); // setando o pino do servo 
        
        sensor1.Initialize(); //inicializando o sensor de temperatura e umidade
  
//Assign the modbus device ID.  
  regBank.setId(1);

/*
modbus registers follow the following format
00001-09999  Digital Outputs, A master device can read and write to these registers
10001-19999  Digital Inputs, A master device can only read the values from these registers
30001-39999  Analog Inputs, A master device can only read the values from these registers
40001-49999  Analog Outputs, A master device can read and write to these registers 

Analog values are 16 bit unsigned words stored with a range of 0-32767
Digital values are stored as bytes, a zero value is OFF and any nonzer value is ON

It is best to configure registers of like type into contiguous blocks.  this
allows for more efficient register lookup and and reduces the number of messages
required by the master to retrieve the data
*/

//Add Analog Output registers 40001-40020 to the register bank
  regBank.add(40001);  
  regBank.add(40002);  
  regBank.add(40003);  
  regBank.add(40004);  
  regBank.add(40005);  
  regBank.add(40006);  
  regBank.add(40007);  
  regBank.add(40008);  
  regBank.add(40009);  
  regBank.add(40010);  
  regBank.add(40011);  
  regBank.add(40012);  
  regBank.add(40013);  
  regBank.add(40014);  
  regBank.add(40015);  
  regBank.add(40016);  
  regBank.add(40017);  
  regBank.add(40018);  
  regBank.add(40019);  
  regBank.add(40020);  

/*
Assign the modbus device object to the protocol handler
This is where the protocol handler will look to read and write
register data.  Currently, a modbus slave protocol handler may
only have one device assigned to it.
*/
  slave._device = &regBank;  

// Initialize the serial port for coms at 9600 baud  
  slave.setBaud(9600);   
}

long previousMillis = 0; // previousMillis irá armazenar o ultimo número da função millis()
long interval = 1000; // intervalo em que o motor irá esperar

void loop()
{
  
 while(1)
 {
    
  //************** SENSOR DE TEMPERATURA E UMIDADE ***********************
  double sensorData[2];
  int result;
  result = sensor1.Read(sensorData);                
  //*************** FIM DE SENSOR *****************************************  
          
 /*Escrevendo no ModBus = regBank.SET */
    regBank.set(40001, (int) 27 + sensorData[0]); //umidade
    regBank.set(40002, (int) sensorData[1]); //temperatura
    regBank.set(40003, (int) ConstMotor); //velocidade moto


 /*Lendo do ModBus = regBank.GET */
    int Comando = regBank.get(40004); //Lendo o valor do Set-Point da temperatura
    int TempAtual =  regBank.get(40002); //Lendo o valor da temperatura

//Na impossibilidade de usar o Delay(0 por truncar a execução do script, vamos partir para um millis().

    unsigned long currentMillis = millis(); //variável currentMillis irá armazenar o tempo
    if(currentMillis - previousMillis > interval) {
        previousMillis = currentMillis; //armazena a variável currentMillis para previousMillis
    
        //verifico a existencia de comando e solto as rotinas...
        if (Comando > 0){
              if (ConstMotor < FimMotor){ 
                if (Comando < TempAtual){ //se o set-point é menor que a temp atual eu acelero o motor
                  ConstMotor = ConstMotor + 10;  
                  val = map(ConstMotor, 0, 1023, 0, 179); 
                  myservo.write(val); 
                  regBank.set(40003, (int) ConstMotor);
                }  
              }

         if (Comando > TempAtual){ //se o set-point é maior que a temp atual eu reduzo o motor
             if (ConstMotor > 10) {
               ConstMotor = ConstMotor - 10;  
               val = map(ConstMotor, 0, 1023, 0, 179); 
               myservo.write(val); 
               regBank.set(40003, (int) ConstMotor);
             }else {
               ConstMotor = 0;  //se já for menor que 10 eu paro o motor de vez
               val = map(ConstMotor, 0, 1023, 0, 179); 
               myservo.write(val); 
               regBank.set(40003, (int) ConstMotor);                
             }
         }

         if (Comando == 0){
            ConstMotor = 0;  
            val = map(ConstMotor, 0, 1023, 0, 179); 
            myservo.write(val); 
            regBank.set(40003, (int) ConstMotor);
          }
        }  
    }
     slave.run(); 
  }
}

sexta-feira, 5 de abril de 2013

Motor brushless funcionando, agora integração ao ScadaBr/Modbus

Salve!


Depois de algumas pesquisas durante a semana, resolvi trocar o motor DC no meu projeto por um motor brushless retirado de um HD antigo. Após algumas pesquisas, descobri  ser possível operar o motor usando um ESC (Eletronic Speed Control) geralmente utilizado em aeromodelismo, decisão que me rendeu algumas horas em busca de circuitos para funcionar o tal motor através do arduino.

Maiores informações sobre o motor e o ESC: O Eletronic Speed Control (ESC) - Motor de corrente contínua sem escovas.

Bom, vamos aos fatos; o primeiro teste do motor ocorreu utilizando um potenciômetro para controlar sua velocidade conforme vídeo abaixo.

Ps: desconsiderem o som, estava assistindo Os Simpsons hehehe


Ou http://youtu.be/P7k-v0p8k0Y

 O código de controle no arduino:


#include <Servo.h>

Servo myservo; // crie objeto Servo para controlar o servomotor

int potpin = 0; // pino analógico usado para conectar o potenciômetro
int val; // variável para ler o valor do pino analógico

void setup() 
   { 
    myservo.attach(9); // ligue o servomotor no pino 9 ao objeto Servo 
    Serial.begin(9600);
   }

void loop() 
   { 
    val = analogRead(potpin); // leia o valor do potenciômetro (valor entre 0 e 1023) 
    val = map(val, 0, 1023, 0, 179); // mapeie para o uso do servo (valor entre 0 and 180     graus) 
    myservo.write(val); // ajuste a posição do servomotor de acordo com o mapeamento
    Serial.println(val);
    delay(400); // aguarde um pouco até o servomotor chegar lá
   }

Créditos: Michal Rinott

Essa semana também consegui ligar um sensor de temperatura e umidade DHT11 com certa estabilidade usando ModBus em ScadaBr, assim que implementar o motor no mesmo sistema, posto os resultados.

terça-feira, 2 de abril de 2013

Começando a diversão...

Buenas!

Hoje finalmente meu Kit com o Arduino e mais alguns componentes chegou, agora começa a diversão...
De projeto inicial pretendo o seguinte:

Medir umidade e temperatura ambiente;
Controlar a aceleração de um motor com uma ventoinha (principio de um inversor de frequência) dentro de uma faixa de operação (set-point);
Monitorar através do ScadaBr, primeiramente via serial e posteriormente com protocolo modbus;
Comandar o set-point de temperatura e motor através do ScadaBr.

Bom, já é um começo, não?




quinta-feira, 28 de março de 2013

Simulando com ModBus

Olá!

Hoje vamos experimentar um pouco a simulação de um CLP rodando o protocolo Modbus no ScadaBR.

A simulação mostra-se muito útil seja para quem está estudando ou para o programador em si, pois elimina a necessidade de um hardware para testes, basta um aplicativo aberto, portas  e endereços configurados e pronto, já podemos nos divetir...

Como ferramenta de simulação, eu costumo usar o PLC Simulator que pode operar tanto em serial como em TCP/IP, nessa demonstração vou usar a segunda opção.

Ps: duas dicas; opte sempre por baixar o binário, pois não vai ser preciso instalar nada, somente descompactar e rodar o .exe. A segunda dica é sempre baixar a chave de registro, caso contrário o programa para de funcionar em 45 minutos e fica apresentando uma msgbox contínua.



Eis a cara do simulador, bem intuitivo e fácil de operar, basta usar os botões e caixas de seleção para suas configurações. 

Um ponto importante é que além de aceitar a escrita de valores, ele também tem um módulo que gera valores aleatórios que podem ser salvos como uma espécie de arquivo de configuração.

Agora vamos ao ScadaBr.

No teste optei pela utilização do ModBus em TCP/IP pela falta de um simulador de serial em meu pc, mas com algumas configurações é possível utilizar os dois módulos, de principio foi criado o canal de comunicação (Data Source) apontando para meu IP (ou o nome da máquina na rede) e a porta padrão (502) e posteriormente foram criadas duas variáveis (Data Points) de leitura/escrita, sendo uma analógica e uma digital.




Ah! importante dizer que na opção "Tipo de transporte" devemos optar pela seleção "TCP com manter-vivo", isso faz com que seja criada uma conexão contínua ao CLP.

Antes da criação dos Data Points, você pode testar a comunicação através do quadro Leitura de dados modbus, onde basta setar a faixa de registro e a quantidade de registros que serão apresentados em sequencia (número de registradores), no exemplo que peguei o endereço 0 da faixa holding registers (acima do 4000) pegando mais 19 em sequencia.

Ps: os valores nessa etapa são apresentados em hexa independentemente da configuração no simulator.



O mesmo vale para as entradas digitais.



Após testes, basta partir para os data points e representações gráficas no ScadaBr.



Em caso de dúvidas ou informações, entre em contato.