Seriële beheerfunksies vir terugvoeraktuators

Die programmering van 'n PLC om u aktuator te beheer, kan een van die moeiliker projekte wees om te onderneem. Dit verg proef en foute, toetsing en 'n hoop geduld; Alhoewel die resultate ongelooflik funksioneel en lonend kan wees.

Die kode in hierdie tutoriaal is 'n volledige program vir 'n funksionele Seriële reageer aktuator. As u die seriële monitor met u PLC gebruik, kan u u Arduino -stelsel met ander rekenaars, modules of outomatiseringstelsels koppel.

Ons sal elke funksie en afdeling van die kode hersien terwyl ons gaan, sodat u spesifieke funksies uit hierdie tutoriaal kan haal. Let daarop dat sommige funksies ander funksies doen wat nie in dieselfde kodeblok ingesluit is nie, dus moet u u kode nagaan om te verseker dat dit behoorlik uitvoer.

Die volledige kode sal aan die einde van hierdie artikel geplaas word. As u die volledige kode wil gebruik, kopieer en plak dit in u IDE -sagteware.

Programoorsig

As dit geïnitialiseer word, sal hierdie program u aktuators tuismaak en kalibreer en die punte van mosie vir die eenheid vind. Dit skuif dan die aktuator na die middelpunt van die beroerte om te wag vir verdere opdragte. U kan dan 'n nommer in u seriële monitor (vanaf u rekenaar) invoer en die aktuator sal na daardie posisie beweeg. Hierdie program raak nie verwar deur die einde van die beroerte nie, en werk met enige Hall Effect-sensor of optiese sensoraktuator.

Onderdelelys

Komponente met 'n (*) is in die Arduino Starter Kit

Funksies

Opsomming van funksies

  1. void setup(): Inisialiseer penne, begin seriële kommunikasie en voer homing- en kalibrasieroetines uit.
  2. void homingRoutine(): Inisieer hom, beweeg die aktuator na volle terugtrekking en stel die minimum beroerte in.
  3. void calibrateActuator(): Inisieer kalibrasie, skuif die aktuator na volle verlenging en stel die maksimum beroerte.
  4. void loop(): Kontrole vir seriële insette, die teikenposisie opdateer en die aktuatorbeweging beheer.
  5. void movement(): Beheer die rigting van aktuatorbeweging gebaseer op die teikenposisie.
  6. void readSensor(): Lees sensorwaardes, werk die posisie en druk sensorlesings op.
  7. void stopMotor(): Stop die aktuatorbeweging.
  8. bool isEndOfStroke(): Tjeks vir die einde van die beroerte en hanteer time -outs.

Veranderlikes

Veranderlikes in u kode moet genoem word voordat dit gebruik word. Die beste programmeringspraktyk is om u veranderlikes aan die bokant van u kode toe te ken en in te stel, om u veranderlikes te verander of 'in te stel'.

Dit is die veranderlikes wat vir hierdie kode gebruik word, met 'n opmerking wat hul funksie en moontlike reeks uiteensit.

//Actuator Specifications
int maxStroke; // Leave undefined, set during calibration
int minStroke; // Leave undefined, set during homing
// Input Variables (Pins) - Change to match your pinout
const int Xpin=10;
const int Rpin=11;
// Sensor Read Pin 1
const int sensorPin=3;
// Hall Effect Sensor Input (Sensor Read pin 2) - Change to match your pinout
const int sensorPin2=4;
int sensorCount2;
// Position Target Function Variables
int targetNumber;
int currentPosition;
int lastPosition=0;
// Motor Control Variables
bool active = false; // Actuator On / Off toggle flag
bool EOSFlag=false; // End of Stroke Flag
// Sensor Readings
int sensorValue;
int lastSensorValue = LOW;
int sensorValue2;
int lastSensorValue2 = LOW;
// Variables for Debounce and End of Stroke Sensing
const unsigned long motionTimeout = 2000;  
// Adjust this value based on your requirements (in milliseconds) 2000=2s
const unsigned long CALIBRATION_TIMEOUT=3000;
// Adjust this value based on your requirements (in milliseconds) 3000=3s
unsigned long lastMotionTime = millis(); //Timer function for EOS function
// Position Variables
unsigned long pulseCount = 0; 
int direction = 0;  // Used for incremental movement count
// 0: Stopped, 1: Moving Forward, -1: Moving Backward

Opstelling/inisialisering

Die nietige opstelling (); Funksie is 'n basis Arduino -funksie wat die PLC initialiseer, die seriële monitor begin en insette en uitsette soos geprogrammeer ken.

Hierdie opstellingsfunksie ken 4 penne toe as insette of uitsette, en voer dan die huis- en kalibrasieroetines uit.

void setup() {
  pinMode(Xpin, OUTPUT);
  pinMode(Rpin, OUTPUT);
  pinMode(sensorPin, INPUT_PULLUP);
  pinMode(sensorPin2, INPUT_PULLUP);
  Serial.begin(115200);

  homingRoutine();
  calibrateActuator();
}

Homing -roetine

Hierdie kode -uittreksel is die funksie om u terugvoeraktuators te huisves. Hierdie kode sal u aktuator intrek totdat die einde van die beroerte opgespoor word, en die posisie 'n waarde van "0" toewys - dan initialiseer dit die kalibrasiefunksie.

In die volledige program word die huis- en kalibrasiefunksies een keer uitgevoer tydens die opstart en nie weer genoem nie.

Hierdie kode -brokkie bel Bykomende funksie (s) wat nie by hierdie blok ingesluit is nie.

void homingRoutine() {
  active=true;
  Serial.println("Homing Initiated");
  digitalWrite(Xpin, LOW);
  digitalWrite(Rpin, HIGH);
  while (!EOSFlag) {
    direction=-1;
    readSensor();
    isEndOfStroke();
    // Move actuator to full retraction
    
  }
  direction=0;
  minStroke=currentPosition;
  Serial.println("Homing Completed");
}

Kalibrasie roetine

Vervolgens het ons ons kalibrasieroetine. Hierdie funksie sal u aktuator volledig uitbrei nadat die huisfunksie die eenheid volledig teruggetrek het. Die doel van hierdie roetine is om die sensorpulse van die een punt van die aktuator se beroerte na die ander te tel. Hierdie waarde word dan as die Maxstroke -veranderlike gestoor en gebruik vir posisionering. Hierdie kode kan aangepas word om terugvoering van potensiometer te verwerk deur spanning na posisie te karteer, eerder as om pulse te tel.

Hierdie kode -brokkie bel Bykomende funksie (s) wat nie by hierdie blok ingesluit is nie.

void calibrateActuator() {
  Serial.println("Calibration Initiated");
  active = true;
  // Reset variables
  pulseCount = 0;
  currentPosition = 0;
  lastMotionTime=millis();

  // Move actuator to full extension
  digitalWrite(Xpin, HIGH);
  digitalWrite(Rpin, LOW);
  direction=1;

  // Wait until the end of stroke is reached during calibration
  while (!isEndOfStroke()) {
    readSensor();

    // Add a timeout condition to avoid infinite loop
    if (millis() - lastMotionTime > motionTimeout) {
      Serial.println("Calibration Timeout");
      stopMotor();
      maxStroke=currentPosition;
      direction=0;
      // Print the calibration results
        Serial.print("Calibration Complete. Minimum Stroke: ");
        Serial.print(minStroke);
        Serial.print(" Maximum Stroke: ");
        Serial.println(maxStroke);
        targetNumber=((maxStroke+minStroke)/2);
        break;
    }
  }
}

 

Lus

Die nietige lus () -funksie is die hoofliggaam van u Arduino -kode. Enigiets wat binne die Loop () -funksie geskryf is, sal tydens die program herhaaldelik uitgevoer word.

Programmeerders let op: Ek vind dit persoonlik die maklikste om die lusfunksie so eenvoudig as moontlik te hou. Dit is die deel van die kode wat sal bel Die meeste ander funksies in die kode, en nie sonder die res van die kode opgehef word.

In hierdie lusfunksie kyk die program na seriële monitor vir insette, werk die teikenposisie met u opdrag op en noem die bewegingsfunksie. Die meeste van die boodskappe wat die PLC na die seriële monitor stuur, kom van hierdie kode.

Daar is 'n Lyn van die kode het kommentaar gelewer Hieronder - wanneer dit ingesluit is, karteer hierdie kode 'n invoer van 0-100 aan die aktuator. D.w.s. U insette is nou 'n persentasie van die aktuator se beroerte. Hierdie reël kan ook gewysig word om ander insette in 'n soortgelyke gekarteerde formaat te gebruik.

Hierdie kode -uittreksel noem addisionele funksie (s) wat nie in hierdie blok ingesluit is nie.

void loop() {
if (!active && Serial.available() > 0) {
  String serialInput = Serial.readStringUntil('\n');
  Serial.print("Received: ");
  Serial.println(serialInput);
  if (serialInput.length() > 0) {
    targetNumber = serialInput.toInt();
    //targetNumber = map(targetNumber, 0, 100, minStroke, maxStroke);

/*If the above line is active, you will input a value between 0-100,
The program will use this input as a % of stroke.*/
Serial.print("Target number: "); Serial.println(targetNumber); EOSFlag = false; } // Clear the serial buffer while (Serial.available()) { Serial.read(); } } if (targetNumber != currentPosition) { active = true; movement(); } /* if (!active) { Serial.println("Waiting for Input"); return; } */ if (active && targetNumber == currentPosition) { stopMotor(); Serial.println("Target Met"); } }

 

Beweging

Die bewegingsfunksie beheer die rigting van die aktuatorbeweging gebaseer op die teikenposisie. Dit is die enigste funksie in hierdie program wat aan die motorbestuurder sê om die aktuator te skuif. 

Hierdie kode -uittreksel noem addisionele funksie (s) wat nie in hierdie blok ingesluit is nie.

void movement() {
  if (targetNumber > currentPosition) {
    digitalWrite(Xpin,HIGH);
    digitalWrite(Rpin,LOW);
    //Serial.println(" Extending");
    direction = 1;
  } else if (targetNumber < currentPosition) {
    digitalWrite(Rpin,HIGH);
    digitalWrite(Xpin,LOW);
    direction = -1;
    //Serial.println("Retracting");
  } else if (targetNumber == currentPosition) {
    stopMotor();
    delay(10);
  }
  if(active) {
    readSensor();
  }
  if (isEndOfStroke()) {
    return;  // Skip further movement actions
  }
}

Sensor lees

Die sensorverwerkingsfunksie lees sensorwaardes, werk posisie en druk sensorlesings op die seriële monitor. Die seriële opdragte kan gebruik word vir ontfouting, of kommentaar gelewer word op 'n minder besige uitlees.

Hierdie kode -stuk kan in enige program gebruik word en gee 'n akkurate lees van pulse van 'n terugvoersensor.

void readSensor() {
  sensorValue = digitalRead(sensorPin);
  if(lastSensorValue != sensorValue) {
    lastSensorValue = sensorValue;
    pulseCount = pulseCount + direction;
    Serial.print("Sensor 1: ");
    Serial.println(pulseCount);
  }
  sensorValue2 = digitalRead(sensorPin2);
  if(lastSensorValue2 != sensorValue2) {
    lastSensorValue2 = sensorValue2;
    sensorCount2=sensorCount2+direction;
    pulseCount = pulseCount + direction;
    Serial.print("Sensor 2: ");
    Serial.println(sensorCount2);
    Serial.print("Current Position: ");
    Serial.println(currentPosition);
  }
  currentPosition = pulseCount;
}

Motorstop en deaktivering

Stop die aktuatorbeweging en stel die eenheid weer in om die seriële monitor te lees vir verdere opdragte. Dit is die enigste kode -stuk in hierdie program wat die aktuator se mosie sal stop.

Hierdie kode -stuk kan in enige program met enige aktuator gebruik word, aangesien dit net die motor afskakel en die 'aktiewe' toestand verander.

void stopMotor() {
 if (active) {
   active=false;
   digitalWrite(Xpin,LOW);
   digitalWrite(Rpin,LOW);
  }
}

Einde van die beroerte -tjek

Kontroleer vir die einde van die beroerte -toestande en hanteer time -outs. As die aktuator die einde van die beroerte tref en ophou beweeg, sal hierdie funksie die aktuator vir nuwe opdraginsette aktiveer en weer instel, selfs al is die teikennommer nog nie bereik nie.

Hierdie kode -brokkie bel Bykomende funksie (s) wat nie by hierdie blok ingesluit is nie.

bool isEndOfStroke() {
  // Check if there is motion (changes in the pulse count)
  if (active && (currentPosition != lastPosition)) {
    lastMotionTime = millis();  // Update the time of the last motion
    lastPosition = currentPosition;
    EOSFlag=false;
  }

  // Check if there is no motion for the specified timeout
  if (active && ((millis() - lastMotionTime) > motionTimeout)) {
    if(EOSFlag!=true) {
      Serial.print("Timeout - ");
      Serial.println("At limit");
      EOSFlag=true;
    }
    direction=0;
    stopMotor();
    return true;
  }
  return false;
}

Volledige kode

//Actuator Specifications
int maxStroke;
int minStroke;

// Input Variables (Pins)
const int Xpin=10;
const int Rpin=11;
const int sensorPin=3;
// Hall Effect Sensor Input
const int sensorPin2=4;
int sensorCount2;


// Motor Function Variables
int targetNumber;
int currentPosition;
int lastPosition=0;
bool active = false;
bool EOSFlag=false;

// Sensor Readings
int sensorValue;
int lastSensorValue = LOW;
int sensorValue2;
int lastSensorValue2 = LOW;

// Variables for Debounce
const unsigned long motionTimeout = 2000;  // Adjust this value based on your requirements (in milliseconds)
const unsigned long CALIBRATION_TIMEOUT=3000; // Adjust this value based on your requirements (in milliseconds)
unsigned long lastMotionTime = millis();

// Position Variables
unsigned long pulseCount = 0;
int direction = 0;  // 0: Stopped, 1: Moving Forward, -1: Moving Backward




void setup() {
  pinMode(Xpin, OUTPUT);
  pinMode(Rpin, OUTPUT);
  pinMode(sensorPin, INPUT_PULLUP);
  pinMode(sensorPin2, INPUT_PULLUP);
  Serial.begin(115200);

  homingRoutine();
  calibrateActuator();
}

void homingRoutine() {
  active=true;
  Serial.println("Homing Initiated");
  digitalWrite(Xpin, LOW);
  digitalWrite(Rpin, HIGH);
  while (!EOSFlag) {
    direction=-1;
    readSensor();
    isEndOfStroke();
    // Move actuator to full retraction
    
  }
  direction=0;
  minStroke=currentPosition;
  Serial.println("Homing Completed");
}

void calibrateActuator() {
  Serial.println("Calibration Initiated");
  active = true;
  // Reset variables
  pulseCount = 0;
  currentPosition = 0;
  lastMotionTime=millis();

  // Move actuator to full extension
  digitalWrite(Xpin, HIGH);
  digitalWrite(Rpin, LOW);
  direction=1;

  // Wait until the end of stroke is reached during calibration
  while (!isEndOfStroke()) {
    readSensor();

    // Add a timeout condition to avoid infinite loop
    if (millis() - lastMotionTime > motionTimeout) {
      Serial.println("Calibration Timeout");
      stopMotor();
      maxStroke=currentPosition;
      direction=0;
      // Print the calibration results
        Serial.print("Calibration Complete. Minimum Stroke: ");
        Serial.print(minStroke);
        Serial.print(" Maximum Stroke: ");
        Serial.println(maxStroke);
        targetNumber=((maxStroke+minStroke)/2);
        break;
    }
  }
}

void loop() {
if (!active && Serial.available() > 0) {
  String serialInput = Serial.readStringUntil('\n');
  Serial.print("Received: ");
  Serial.println(serialInput);
  if (serialInput.length() > 0) {
    targetNumber = serialInput.toInt();
    Serial.print("Target number: ");
    Serial.println(targetNumber);
    EOSFlag = false;
  }
  // Clear the serial buffer
  while (Serial.available()) {
    Serial.read();
  }
}

  if (targetNumber != currentPosition) {
    active = true;
    movement();
  } 
  /*
  if (!active) {
   Serial.println("Waiting for Input"); 
   return;
  } */
  if (active && targetNumber == currentPosition) {
   stopMotor();
   Serial.println("Target Met");
  }
}

void movement() {
  if (targetNumber > currentPosition) {
    digitalWrite(Xpin,HIGH);
    digitalWrite(Rpin,LOW);
    //Serial.println(" Extending");
    direction = 1;
  } else if (targetNumber < currentPosition) {
    digitalWrite(Rpin,HIGH);
    digitalWrite(Xpin,LOW);
    direction = -1;
    //Serial.println("Retracting");
  } else if (targetNumber == currentPosition) {
    stopMotor();
    delay(10);
  }
  if(active) {
    readSensor();
  }
  if (isEndOfStroke()) {
    return;  // Skip further movement actions
  }
}

void readSensor() {
  sensorValue = digitalRead(sensorPin);
  if(lastSensorValue != sensorValue) {
    lastSensorValue = sensorValue;
    pulseCount = pulseCount + direction;
    Serial.print("Sensor 1: ");
    Serial.println(pulseCount);
  }
  sensorValue2 = digitalRead(sensorPin2);
  if(lastSensorValue2 != sensorValue2) {
    lastSensorValue2 = sensorValue2;
    sensorCount2=sensorCount2+direction;
    pulseCount = pulseCount + direction;
    Serial.print("Sensor 2: ");
    Serial.println(sensorCount2);
    Serial.print("Current Position: ");
    Serial.println(currentPosition);
  }
  currentPosition = pulseCount;
}


void stopMotor() {
 if (active) {
   active=false;
   digitalWrite(Xpin,LOW);
   digitalWrite(Rpin,LOW);
  }
}

bool isEndOfStroke() {
  // Check if there is motion (changes in the pulse count)
  if (active && (currentPosition != lastPosition)) {
    lastMotionTime = millis();  // Update the time of the last motion
    lastPosition = currentPosition;
    EOSFlag=false;
  }

  // Check if there is no motion for the specified timeout
  if (active && ((millis() - lastMotionTime) > motionTimeout)) {
    if(EOSFlag!=true) {
      Serial.print("Timeout - ");
      Serial.println("At limit");
      EOSFlag=true;
    }
    direction=0;
    stopMotor();
    return true;
  }
  return false;
}
Share This Article
Tags: