Posted by : MC 28 Eylül 2015 Pazartesi

Birçok insan arduinonun endüstriyel boyutta kullanılıp, kullanılamayacağı konusunda tartışma içerisinde.
Bunun tam olarak cevabını sizlere veremesemde,arduino için yazılmış ve endüstriyel uygulamalarda kullanılması kaçınılmaz kütüphanelerden bahsetmek istiyorum.

1. Modbus Kütüphanesi :

Endüstride birçok cihaz ve plc kendi aralarında ya da scada gibi yönetim sistemleri ile haberleşme durumundadır.Modbus ise endüstriyel cihazlar arasında haberleşme metodu olarak kullanılan en yaygın yöntemlerden biridir.


Master Arduino

#include <SoftwareSerial.h>
/*-----( Declare Constants and Pin Numbers )-----*/
#define SSerialRX        10  //Serial Receive pin
#define SSerialTX        11  //Serial Transmit pin

#define SSerialTxControl 3   //RS485 Direction control

#define RS485Transmit    HIGH
#define RS485Receive     LOW

#define Pin13LED         13

/*-----( Declare objects )-----*/
SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX

/*-----( Declare Variables )-----*/
int byteReceived;
int byteSend;

void setup()   /****** SETUP: RUNS ONCE ******/
{
  // Start the built-in serial port, probably to Serial Monitor
  Serial.begin(9600);
  Serial.println("YourDuino.com SoftwareSerial remote loop example");
  Serial.println("Use Serial Monitor, type in upper window, ENTER");
  
  pinMode(Pin13LED, OUTPUT);   
  pinMode(SSerialTxControl, OUTPUT);    
  
  digitalWrite(SSerialTxControl, RS485Receive);  // Init Transceiver   
  
  // Start the software serial port, to another device
  RS485Serial.begin(4800);   // set the data rate 

}//--(end setup )---


void loop()   /****** LOOP: RUNS CONSTANTLY ******/
{
  digitalWrite(Pin13LED, HIGH);  // Show activity
  if (Serial.available())
  {
    byteReceived = Serial.read();
    
    digitalWrite(SSerialTxControl, RS485Transmit);  // Enable RS485 Transmit   
    RS485Serial.write(byteReceived);          // Send byte to Remote Arduino
    
    digitalWrite(Pin13LED, LOW);  // Show activity    
    delay(10);
    digitalWrite(SSerialTxControl, RS485Receive);  // Disable RS485 Transmit       
  }
  
  if (RS485Serial.available())  //Look for data from other Arduino
   {
    digitalWrite(Pin13LED, HIGH);  // Show activity
    byteReceived = RS485Serial.read();    // Read received byte
    Serial.write(byteReceived);        // Show on Serial Monitor
    delay(10);
    digitalWrite(Pin13LED, LOW);  // Show activity   
   }  

}//--(end main loop )---

/*-----( Declare User-written Functions )-----*/

//NONE
//*********( THE END )***********

Slave Arduino

#include <SoftwareSerial.h>
/*-----( Declare Constants and Pin Numbers )-----*/
#define SSerialRX        10  //Serial Receive pin
#define SSerialTX        11  //Serial Transmit pin

#define SSerialTxControl 3   //RS485 Direction control
#define RS485Transmit    HIGH
#define RS485Receive     LOW

#define Pin13LED         13

/*-----( Declare objects )-----*/
SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX

/*-----( Declare Variables )-----*/
int byteReceived;
int byteSend;

void setup()   /****** SETUP: RUNS ONCE ******/
{
  // Start the built-in serial port, probably to Serial Monitor
  Serial.begin(9600);
  Serial.println("SerialRemote");  // Can be ignored
  
  pinMode(Pin13LED, OUTPUT);   
  pinMode(SSerialTxControl, OUTPUT);  
  
  digitalWrite(SSerialTxControl, RS485Receive);  // Init Transceiver
  
  // Start the software serial port, to another device
  RS485Serial.begin(4800);   // set the data rate 
}//--(end setup )---


void loop()   /****** LOOP: RUNS CONSTANTLY ******/
{
  //Copy input data to output  
  if (RS485Serial.available()) 
  {
    byteSend = RS485Serial.read();   // Read the byte 
    
    digitalWrite(Pin13LED, HIGH);  // Show activity
    delay(10);              
    digitalWrite(Pin13LED, LOW);   
    
    digitalWrite(SSerialTxControl, RS485Transmit);  // Enable RS485 Transmit    
    RS485Serial.write(byteSend); // Send the byte back
    delay(10);   
    digitalWrite(SSerialTxControl, RS485Receive);  // Disable RS485 Transmit      
//    delay(100);
  }
2. PID Kütüphanesi:

Endüstriyel otomasyon projelerinde kontrol metodlarının olmazsa olmazıdır.Birçok uygulamada giriş ve çıkışa bağımlı olarak pid üzerinden kontrol metodları uygulanır.Arduino için pid kütüphanesi kullanmaz endüstriye bazda bir uygulama yapmak istiyorsak kaçınılmaz.

pid.h :

#ifndef PID_v1_h
#define PID_v1_h
#define LIBRARY_VERSION 1.1.1
class PID
{
public:
//Constants used in some of the functions below

#define AUTOMATIC 1

#define MANUAL 0

#define DIRECT 0

#define REVERSE 1

//commonly used functions **************************************************************************

PID(double*, double*, double*, // * constructor. links the PID to the Input, Output, and

double, double, double, int); // Setpoint. Initial tuning parameters are also set here



void SetMode(int Mode); // * sets PID to either Manual (0) or Auto (non-0)



bool Compute(); // * performs the PID calculation. it should be

// called every time loop() cycles. ON/OFF and

// calculation frequency can be set using SetMode

// SetSampleTime respectively



void SetOutputLimits(double, double); //clamps the output to a specific range. 0-255 by default, but

//it's likely the user will want to change this depending on

//the application

//available but not commonly used functions ********************************************************

void SetTunings(double, double, // * While most users will set the tunings once in the

double); // constructor, this function gives the user the option

// of changing tunings during runtime for Adaptive control

void SetControllerDirection(int); // * Sets the Direction, or "Action" of the controller. DIRECT

// means the output will increase when error is positive. REVERSE

// means the opposite. it's very unlikely that this will be needed

// once it is set in the constructor.

void SetSampleTime(int); // * sets the frequency, in Milliseconds, with which

// the PID calculation is performed. default is 100

//Display functions ****************************************************************

double GetKp(); // These functions query the pid for interal values.

double GetKi(); // they were created mainly for the pid front-end,

double GetKd(); // where it's important to know what is actually

int GetMode(); // inside the PID.

int GetDirection(); //

private:

void Initialize();

double dispKp; // * we'll hold on to the tuning parameters in user-entered

double dispKi; // format for display purposes

double dispKd; //

double kp; // * (P)roportional Tuning Parameter

double ki; // * (I)ntegral Tuning Parameter

double kd; // * (D)erivative Tuning Parameter

int controllerDirection;

double *myInput; // * Pointers to the Input, Output, and Setpoint variables

double *myOutput; // This creates a hard link between the variables and the

double *mySetpoint; // PID, freeing the user from having to constantly tell us

// what these values are. with pointers we'll just know.

unsigned long lastTime;

double ITerm, lastInput;

unsigned long SampleTime;

double outMin, outMax;

bool inAuto;

};

#endif

pid.cpp:



#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <PID_v1.h>
/*Constructor (...)*********************************************************
* The parameters specified here are those for for which we can't set up
* reliable defaults, so we need to have the user set them.
***************************************************************************/
PID::PID(double* Input, double* Output, double* Setpoint,
double Kp, double Ki, double Kd, int ControllerDirection)
{
myOutput = Output;
myInput = Input;
mySetpoint = Setpoint;
inAuto = false;
PID::SetOutputLimits(0, 255); //default output limit corresponds to
//the arduino pwm limits
SampleTime = 100; //default Controller Sample Time is 0.1 seconds
PID::SetControllerDirection(ControllerDirection);
PID::SetTunings(Kp, Ki, Kd);
lastTime = millis()-SampleTime;
}

/* Compute() **********************************************************************
* This, as they say, is where the magic happens. this function should be called
* every time "void loop()" executes. the function will decide for itself whether a new
* pid Output needs to be computed. returns true when the output is computed,
* false when nothing has been done.
**********************************************************************************/
bool PID::Compute()
{
if(!inAuto) return false;
unsigned long now = millis();
unsigned long timeChange = (now - lastTime);
if(timeChange>=SampleTime)
{
/*Compute all the working error variables*/
double input = *myInput;
double error = *mySetpoint - input;
ITerm+= (ki * error);
if(ITerm > outMax) ITerm= outMax;
else if(ITerm < outMin) ITerm= outMin;
double dInput = (input - lastInput);
/*Compute PID Output*/
double output = kp * error + ITerm- kd * dInput;
if(output > outMax) output = outMax;
else if(output < outMin) output = outMin;
*myOutput = output;
/*Remember some variables for next time*/
lastInput = input;
lastTime = now;
return true;
}
else return false;
}

/* SetTunings(...)*************************************************************
* This function allows the controller's dynamic performance to be adjusted.
* it's called automatically from the constructor, but tunings can also
* be adjusted on the fly during normal operation
******************************************************************************/
void PID::SetTunings(double Kp, double Ki, double Kd)
{
if (Kp<0 || Ki<0 || Kd<0) return;
dispKp = Kp; dispKi = Ki; dispKd = Kd;
double SampleTimeInSec = ((double)SampleTime)/1000;
kp = Kp;
ki = Ki * SampleTimeInSec;
kd = Kd / SampleTimeInSec;
if(controllerDirection ==REVERSE)
{
kp = (0 - kp);
ki = (0 - ki);
kd = (0 - kd);
}
}
/* SetSampleTime(...) *********************************************************
* sets the period, in Milliseconds, at which the calculation is performed
******************************************************************************/
void PID::SetSampleTime(int NewSampleTime)
{
if (NewSampleTime > 0)
{
double ratio = (double)NewSampleTime
/ (double)SampleTime;
ki *= ratio;
kd /= ratio;
SampleTime = (unsigned long)NewSampleTime;
}
}
/* SetOutputLimits(...)****************************************************
* This function will be used far more often than SetInputLimits. while
* the input to the controller will generally be in the 0-1023 range (which is
* the default already,) the output will be a little different. maybe they'll
* be doing a time window and will need 0-8000 or something. or maybe they'll
* want to clamp it from 0-125. who knows. at any rate, that can all be done
* here.
**************************************************************************/
void PID::SetOutputLimits(double Min, double Max)
{
if(Min >= Max) return;
outMin = Min;
outMax = Max;
if(inAuto)
{
if(*myOutput > outMax) *myOutput = outMax;
else if(*myOutput < outMin) *myOutput = outMin;
if(ITerm > outMax) ITerm= outMax;
else if(ITerm < outMin) ITerm= outMin;
}
}
/* SetMode(...)****************************************************************
* Allows the controller Mode to be set to manual (0) or Automatic (non-zero)
* when the transition from manual to auto occurs, the controller is
* automatically initialized
******************************************************************************/
void PID::SetMode(int Mode)
{
bool newAuto = (Mode == AUTOMATIC);
if(newAuto == !inAuto)
{ /*we just went from manual to auto*/
PID::Initialize();
}
inAuto = newAuto;
}
/* Initialize()****************************************************************
* does all the things that need to happen to ensure a bumpless transfer
* from manual to automatic mode.
******************************************************************************/
void PID::Initialize()
{
ITerm = *myOutput;
lastInput = *myInput;
if(ITerm > outMax) ITerm = outMax;
else if(ITerm < outMin) ITerm = outMin;
}
/* SetControllerDirection(...)*************************************************
* The PID will either be connected to a DIRECT acting process (+Output leads
* to +Input) or a REVERSE acting process(+Output leads to -Input.) we need to
* know which one, because otherwise we may increase the output when we should
* be decreasing. This is called from the constructor.
******************************************************************************/
void PID::SetControllerDirection(int Direction)
{
if(inAuto && Direction !=controllerDirection)
{
kp = (0 - kp);
ki = (0 - ki);
kd = (0 - kd);
}
controllerDirection = Direction;
}
/* Status Funcions*************************************************************
* Just because you set the Kp=-1 doesn't mean it actually happened. these
* functions query the internal state of the PID. they're here for display
* purposes. this are the functions the PID Front-end uses for example
******************************************************************************/
double PID::GetKp(){ return dispKp; }
double PID::GetKi(){ return dispKi;}
double PID::GetKd(){ return dispKd;}
int PID::GetMode(){ return inAuto ? AUTOMATIC : MANUAL;}
int PID::GetDirection(){ return controllerDirection;}
3. Map Fonksiyonu:

Map fonksiyonunu bizim için çok önemli kılan özelliği, belirli bir giriş aralığına göre çıkış aralığı tanımlayabilmemiz.Buda bize endüstriyel otomasyon bazında gerek kompanzasyon gerekse analog çıkış atamak istediğimizde belirli set değerleri arasında bir çıkış verebilmemize olanak sağlıyor.

/* Map an analog value to 8 bits (0 to 255) */
void setup() {}

void loop()
{
  int val = analogRead(0);
  val = map(val, 0, 1023, 0, 255);
  analogWrite(9, val);
}

4. Sofware Serial :

Endüstriyel birçok projede birden fazla cihazla haberleşmede daha önce bahsettiğimiz modbus protokolünün yanı sıra birden fazla seri haberleşme metoduna da ihtiyaç duyulabilmektedir.

SoftwareSerial mySerial(10, 11); // RX, TX

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(57600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  Serial.println("Goodnight moon!");

  // set the data rate for the SoftwareSerial port
  mySerial.begin(4800);
  mySerial.println("Hello, world?");
}

void loop() { // run over and over
  if (mySerial.available()) {
    Serial.write(mySerial.read());
  }
  if (Serial.available()) {
    mySerial.write(Serial.read());
  }
}


yorumlarınız bizim için önemli

Bültene abone ol | Yorumlara abone ol

ELEKTRO BLOGGER A HOŞGELDINIZ

ARAMA YAP

EN COK OKUNANLAR

- Copyright © ELEKTRO-BLOGGER Blogger