Serienkontrollfunktionen für Feedback -Aktuatoren

Das Programmieren einer SPS zur Kontrolle Ihres Aktuators kann eines der schwierigeren Projekte sein. Es erfordert Versuch und Irrtum, Tests und eine Menge Geduld; Obwohl die Ergebnisse unglaublich funktional und lohnend sein können.

Der Code in diesem Tutorial ist ein vollständiges Programm für eine Funktionale Serieller Antriebsantrieb. Durch die Verwendung des seriellen Monitors mit Ihrer SPS können Sie Ihr Arduino -System mit anderen Computern, Modulen oder Automatisierungssystemen interpretieren.

Wir werden jede Funktion und jeden Abschnitt des Codes während des gesamten Zeitraums überprüfen, sodass Sie bestimmte Funktionen aus diesem Tutorial herausholen können. Bitte beachten Sie, dass einige Funktionen andere Funktionen aufrufen, die nicht im selben Codeblock enthalten sind. Sie müssen daher über Ihren Code überprüfen, um sicherzustellen, dass er ordnungsgemäß ausgeführt wird.

Der vollständige Code wird am Ende dieses Artikels veröffentlicht. Wenn Sie den vollständigen Code verwenden möchten, kopieren Sie ihn und fügen Sie ihn in Ihre IDE -Software ein.

Programmübersicht

Bei der Initialisierung wird dieses Programm Ihre Aktuatoren nach Hause und kalibrieren und finden die Bewegungsende für das Gerät. Anschließend bewegt es den Aktuator zum mittleren Schlaganfall, um auf weitere Befehle zu warten. Sie können dann eine Nummer in Ihren seriellen Monitor (von Ihrem PC) eingeben, und der Aktuator wird zu dieser Position übergeht. Dieses Programm wird nicht durch die Abschlusspartierung am Ende des Schlaganfalls verwirrt und arbeitet mit einem Hall-Effect-Sensor oder optischen Sensor-Aktuator zusammen.

Teileliste

Komponenten mit einem (*) sind in der enthalten Arduino Starter Kit

Funktionen

Zusammenfassung der Funktionen

  1. void setup(): Initialisiert die Stifte, startet serielle Kommunikation und führt Homing- und Kalibrierungsroutinen aus.
  2. void homingRoutine(): Initiiert Homing, bewegt den Stellantrieb auf den vollständigen Rückzug und legt den minimalen Schlaganfall fest.
  3. void calibrateActuator(): Initiiert die Kalibrierung, bewegt den Stellantrieb auf die volle Erweiterung und legt den maximalen Schlaganfall fest.
  4. void loop(): Überprüft nach seriellen Eingaben, aktualisiert die Zielposition und steuert die Aktuatorbewegung.
  5. void movement(): Steuert die Richtung der Aktuatorbewegung basierend auf der Zielposition.
  6. void readSensor(): Liest Sensorwerte, aktualisiert die Position und druckt Sensorwerte.
  7. void stopMotor(): Stoppt die Aktuatorbewegung.
  8. bool isEndOfStroke(): Überprüft nach dem Ende der Schlaganfallbedingungen und übernimmt Timeouts.

Variablen

Variablen in Ihrem Code müssen aufgerufen werden, bevor sie verwendet werden. Die beste Programmierungspraxis besteht darin, Ihre Variablen oben in Ihrem Code zuzuweisen und festzulegen, um Ihre Variablen zu ändern oder zu „stimmen“.

Dies sind die Variablen, die für diesen Code verwendet werden, mit einem Kommentar, der ihre Funktion und einen möglichen Bereich erläutert.

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

Setup/Initialisierung

Das void setup (); Funktion ist eine Basis -Arduino -Funktion, die die SPS initialisiert, den seriellen Monitor beginnt und Eingänge und Ausgänge als programmiert zuweist.

Diese Setup -Funktion weist 4 Pins als Eingänge oder Ausgänge zu und führt dann die Homing- und Kalibrierungsroutinen aus.

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

  homingRoutine();
  calibrateActuator();
}

Homing -Routine

Dieser Code -Snippet ist die Funktion, um Ihre Feedback -Aktuatoren zu betreuen. Dieser Code zieht Ihren Aktuator bis zum Ende des Schlaganfalls zurück und weist diese Position einen Wert von "0" zu - dann initialisiert er die Kalibrierungsfunktion.

Im vollständigen Programm werden die Homing- und Kalibrierungsfunktionen beim Start einmal ausgeführt und nicht wieder aufgerufen.

Dieser Code -Snippet -Aufrufe Zusätzliche Funktionen, die in diesem Block nicht enthalten sind.

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

Kalibrierungsroutine

Als nächstes haben wir unsere Kalibrierungsroutine. Diese Funktion erweitert Ihren Aktuator vollständig, nachdem die Homing -Funktion das Gerät vollständig zurückgezogen hat. Der Zweck dieser Routine ist es, die Sensorimpulse von einem Ende des Schlagantriebs zum anderen zu zählen. Dieser Wert wird dann als Maxstroke -Variable gespeichert und zur Positionierung verwendet. Dieser Code kann geändert werden, um das Potentiometer -Feedback zu verarbeiten, indem Spannung auf Position abgebildet wird, anstatt Impulse zu zählen.

Dieser Code -Snippet -Aufrufe Zusätzliche Funktionen, die in diesem Block nicht enthalten sind.

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

 

Schleife

Die void Loop () -Funktion ist die Hauptkörper Ihr Arduino -Code. Alles, was in der Loop () -Funktion geschrieben wurde, wird während des Programms wiederholt ausgeführt.

Programmierer Hinweis: Ich persönlich finde es am einfachsten, die Schleifenfunktion so einfach wie möglich zu halten. Dies ist der Teil des Codes, der anruft die meisten anderen Funktionen im Code und kann nicht ohne den Rest des Codes angehoben werden.

In dieser Schleifenfunktion prüft das Programm nach serieller Monitor für die Eingabe, aktualisiert die Zielposition mit Ihrem Befehl und ruft die Bewegungsfunktion auf. Die meisten Nachrichten, die die SPS an den seriellen Monitor sendet, stammen von diesem Code -Snippet.

Da ist a Codezeile kommentierte Im Folgenden - wenn enthalten ist diese Codezeile eine Eingabe von 0-100 an den Aktuator. D.h. Ihre Eingabe ist jetzt ein Prozentsatz des Schlagantriebs des Aktuators. Diese Zeile kann auch so geändert werden, dass andere Eingänge in einem ähnlichen kartierten Format verwendet werden.

Dieser Code -Snippet ruft zusätzliche Funktionen auf, die nicht in diesem Block enthalten sind.

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

 

Bewegung

Die Bewegungsfunktion steuert die Richtung der Aktuatorbewegung basierend auf der Zielposition. Dies ist die einzige Funktion in diesem Programm, die dem Motor -Treiber sagt, dass er den Aktuator verschieben soll. 

Dieser Code -Snippet ruft zusätzliche Funktionen auf, die nicht in diesem Block enthalten sind.

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 lesen

Die Sensorverarbeitungsfunktion liest Sensorwerte, aktualisiert die Position und druckt Sensorwerte in den seriellen Monitor. Die seriellen Befehle können zum Debuggen verwendet werden oder für eine weniger betrügerische Anzeige kommentiert werden.

Dieser Code -Snippet kann in jedem Programm verwendet werden und enthält eine genaue Lektüre von Impulsen von einem Feedback -Sensor.

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 -Stopp und Deaktivierung

Stoppt die Antriebsbewegung und wird das Gerät wieder eingesetzt, um den Serienmonitor für weitere Befehle zu lesen. Dies ist das einzige Code -Snippet in diesem Programm, das den Antrag des Aktuators stoppt.

Dieser Code -Snippet kann in jedem Programm mit jedem Aktuator verwendet werden, da er nur den Motor ausschaltet und den „aktiven“ Zustand ändert.

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

Ende des Schlaganfallschecks

Überprüft nach dem Ende der Schlaganfallbedingungen und übernimmt Timeouts. Wenn der Aktuator Ende des Schlaganfalls einsetzt und sich nicht mehr bewegen, wird diese Funktion den Aktuator für neue Befehlseingänge ausgelöst und setzt, auch wenn die Zielnummer noch nicht erreicht wurde.

Dieser Code -Snippet -Aufrufe Zusätzliche Funktionen, die in diesem Block nicht enthalten sind.

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

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