Seriële besturingsfuncties voor feedbackactuatoren

Het programmeren van een PLC om uw actuator te besturen, kan een van de moeilijkere projecten zijn om uit te voeren. Het vereist vallen en opstaan, testen en een hoop geduld; Hoewel de resultaten ongelooflijk functioneel en lonend kunnen zijn.

De code in deze tutorial is een compleet programma voor een functioneel Seriële responsieve actuator. Door de seriële monitor met uw PLC te gebruiken, kunt u uw Arduino -systeem koppelen aan andere computers, modules of automatiseringssystemen.

We zullen elke functie en het gedeelte van de code bekijken terwijl we gaan, zodat u specifieke functies uit deze tutorial kunt halen. Let op, sommige functies roepen aan op andere functies die niet in hetzelfde codeblok zijn opgenomen, dus u moet uw code controleren om ervoor te zorgen dat deze correct wordt uitgevoerd.

De volledige code wordt aan het einde van dit artikel geplaatst. Als u de volledige code wilt gebruiken, kopieert en plakt u deze in uw IDE -software.

Programma -overzicht

Wanneer geïnitialiseerd, wordt dit programma uw actuatoren thuis en gekalibreerd, waarbij u de uiteinden van beweging voor de eenheid vindt. Vervolgens verplaatst het de actuator naar het middelste punt van een slag om te wachten op verdere commando's. U kunt vervolgens een nummer invoeren in uw seriële monitor (van uw pc) en de actuator zal naar die positie gaan. Dit programma raakt niet in de war door afsluiting van het einde van de slag en werkt samen met een Hall-effectsensor of optische sensoractuator.

Onderdelenlijst

Componenten met een (*) zijn opgenomen in de Arduino Starter Kit

Functie

Samenvatting van functies

  1. void setup(): Initialiseert pinnen, start seriële communicatie en voert homing- en kalibratieroutines uit.
  2. void homingRoutine(): Homing initieert, beweegt de actuator naar volledige intrekking en stelt de minimale slag in.
  3. void calibrateActuator(): Kalibratie initieert, verplaatst de actuator naar volledige extensie en stelt de maximale slag in.
  4. void loop(): Controleert op seriële invoer, werkt de doelpositie bij en regelt de actuatorbeweging.
  5. void movement(): Regelt de richting van actuatorbeweging op basis van de doelpositie.
  6. void readSensor(): Leest sensorwaarden, updates positie en drukt sensorwaarden af.
  7. void stopMotor(): Stopt de actuatorbeweging.
  8. bool isEndOfStroke(): Controleert op het einde van de slagcondities en verwerkt time -outs.

Variabelen

Variabelen in uw code moeten worden aangeroepen voordat ze worden gebruikt. De beste programmeerpraktijk is om uw variabelen bovenaan uw code toe te wijzen en in te stellen, om uw variabelen te wijzigen of te 'afstemmen'.

Dit zijn de variabelen die voor deze code worden gebruikt, met een opmerking die hun functie en mogelijk bereik uitlegt.

//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

Instel/initialisatie

De void setup (); Functie is een basis Arduino -functie die de PLC initialiseert, de seriële monitor begint en ingangen en uitgangen zoals geprogrammeerd toewijst.

Deze instellingenfunctie kent 4 pins toe als ingangen of uitgangen en voert vervolgens de homing- en kalibratieroutines uit.

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

  homingRoutine();
  calibrateActuator();
}

Homingroutine

Dit codefragment is de functie om uw feedback -actuatoren te homo's. Deze code intrekt uw actuator totdat het einde van de slag is gedetecteerd en zal die positie een waarde van "0" toewijzen - vervolgens initialiseert deze de kalibratiefunctie.

In het volledige programma worden de homing- en kalibratiefuncties eenmaal, tijdens het opstarten uitgevoerd en niet opnieuw opgeroepen.

Dit code -fragment roept Extra functie (s) die niet in dit blok zijn opgenomen.

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");
}

Kalibratieroutine

Vervolgens hebben we onze kalibratieroutine. Deze functie zal uw actuator volledig uitbreiden nadat de homing -functie de eenheid volledig heeft ingetrokken. Het doel van deze routine is om de sensorpulsen te tellen van het ene uiteinde van de slag van de actuator naar het andere. Deze waarde wordt vervolgens opgeslagen als de MaxStrroke -variabele en gebruikt voor positionering. Deze code kan worden gewijzigd om feedback van potentiometer te verwerken door spanning in kaart te brengen naar positioneren, in plaats van pulsen te tellen.

Dit code -fragment roept Extra functie (s) die niet in dit blok zijn opgenomen.

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

De functie void loop () is de hoofdlichaam van uw Arduino -code. Alles wat in de functie Loop () is geschreven, wordt tijdens het programma herhaaldelijk uitgevoerd.

Programmeurs Opmerking: Ik vind het persoonlijk het gemakkelijkst om de lusfunctie zo eenvoudig mogelijk te houden. Dit is het deel van de code dat zal bellen de meeste andere functies in de code, en niet worden opgeheven zonder de rest van de code.

In deze lusfunctie controleert het programma op seriële monitor op invoer, werkt de doelpositie bij met uw opdracht en roept de bewegingsfunctie op. De meeste berichten die de PLC naar de seriële monitor stuurt, komen uit dit codefragment.

Er is een Gerechtelijke regel van code Hieronder - Wanneer opgenomen, geeft deze codelijn een invoer van 0-100 toe aan de actuator. D.w.z. Uw invoer is nu een percentage van de beroerte van de actuator. Deze lijn kan ook worden aangepast om andere ingangen in een vergelijkbaar in kaart gebracht formaat te gebruiken.

Dit codefragment roept extra functie (s) aan die niet in dit blok zijn opgenomen.

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

De bewegingsfunctie regelt de richting van actuatorbeweging op basis van de doelpositie. Dit is de enige functie in dit programma die de motorrijder vertelt de actuator te verplaatsen. 

Dit codefragment roept extra functie (s) aan die niet in dit blok zijn opgenomen.

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 gelezen

De sensorverwerkingsfunctie leest sensorwaarden, werkt de positie bij en drukt sensorwaarden af ​​naar de seriële monitor. De seriële opdrachten kunnen worden gebruikt voor foutopsporing, of becommentarieerd voor een minder-drukke uitlezing.

Dit codefragment kan in elk programma worden gebruikt en geeft een nauwkeurige lezing van pulsen van een feedbacksensor.

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;
}

Motor stoppen en deactivering

Stopt de actuatorbeweging en maakt het apparaat opnieuw in om de seriële monitor te lezen voor verdere opdrachten. Dit is het enige codefragment in dit programma dat de motie van de actuator zal stoppen.

Dit codefragment kan worden gebruikt in elk programma met elke actuator, omdat het de motor gewoon uitschakelt en de 'actieve' status verandert.

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

Einde van een slagcontrole

Controleert op het einde van de slagcondities en verwerkt time -outs. Wanneer de actuator het einde van de slag bereikt en stopt met bewegen, zal deze functie de actuator activeren en opnieuw instellen voor nieuwe opdrachtinvoer, zelfs als het doelnummer nog niet is bereikt.

Dit code -fragment roept Extra functie (s) die niet in dit blok zijn opgenomen.

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 code

//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: