フィードバックアクチュエーターのシリアル制御機能

アクチュエータを制御するためのPLCのプログラミングは、実施するのがより困難なプロジェクトの1つです。試行錯誤、テスト、忍耐力が必要です。結果は非常に機能的でやりがいがありますが。

このチュートリアルのコードは、機能的な完全なプログラムです シリアルレスポンシブアクチュエータ。 PLCでシリアルモニターを使用すると、Arduinoシステムと他のコンピューター、モジュール、または自動化システムとインターフェイスできます。

このチュートリアルから特定の関数を引き出すことができるように、コードの各機能とセクションを確認します。一部の関数は、同じコードブロックに含まれていない他の関数を呼び出すことに注意してください。そのため、コードが適切に実行されることを確認するためにコードを確認する必要があります。

完全なコードは、この記事の最後に投稿されます。完全なコードを使用したい場合は、IDEソフトウェアにコピーして貼り付けます。

プログラムの概要

初期化されると、このプログラムはアクチュエータを故郷と校正し、ユニットの動きの終わりを見つけます。次に、アクチュエータをストロークの中間点に移動して、さらなるコマンドを待ちます。その後、数値を(PCから)シリアルモニターに入力すると、アクチュエーターがその位置に移動します。このプログラムは、脳卒中の終了シャットオフによって混乱することはなく、ホールエフェクトセンサーまたは光学センサーアクチュエータで動作します。

部品リスト

(*)のコンポーネントはに含まれています Arduinoスターターキット

関数

関数の概要

  1. void setup():ピンを初期化し、シリアル通信を開始し、ホーミングおよびキャリブレーションルーチンを実行します。
  2. void homingRoutine():ホーミングを開始し、アクチュエータを完全に撤回するように動かし、最小ストロークを設定します。
  3. void calibrateActuator():キャリブレーションを開始し、アクチュエータを完全な拡張に移動し、最大ストロークを設定します。
  4. void loop():シリアル入力のチェック、ターゲット位置を更新し、アクチュエータの動きを制御します。
  5. void movement():ターゲット位置に基づいてアクチュエータの動きの方向を制御します。
  6. void readSensor():センサーの値を読み取り、ポジションを更新し、センサーの測定値を印刷します。
  7. void stopMotor():アクチュエータの動きを停止します。
  8. bool isEndOfStroke():ストローク条件の終了をチェックし、タイムアウトを処理します。

変数

コードの変数は、使用する前に呼び出さなければなりません。最良のプログラミングプラクティスは、変数をコードの上部に割り当てて設定し、変数を変更または「チューニング」することです。

これらはこのコードに使用される変数であり、その機能と可能な範囲を説明するコメントがあります。

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

セットアップ/初期化

void setup();関数は、PLCを初期化し、シリアルモニターを開始し、プログラムとして入力と出力を割り当てるベースArduino関数です。

このセットアップ関数は、4つのピンを入力または出力として割り当て、ホーミングおよびキャリブレーションルーチンを実行します。

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

  homingRoutine();
  calibrateActuator();
}

ホーミングルーチン

このコードスニペットは、フィードバックアクチュエーターをホーミングする機能です。このコードは、ストロークの終了が検出されるまでアクチュエータを撤回し、その位置を「0」の値を割り当てます - 次に、キャリブレーション関数を初期化します。

完全なプログラムでは、起動中にホーミングおよびキャリブレーション機能が一度実行され、再び呼び出されません。

このコードスニペット呼び出し このブロックに含まれていない追加の関数。

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

キャリブレーションルーチン

次に、キャリブレーションルーチンがあります。この関数は、ホーミング機能がユニットを完全に格納した後、アクチュエータを完全に拡張します。このルーチンの目的は、アクチュエーターのストロークの一方の端からもう一方の端にセンサーパルスをカウントすることです。この値は、Maxstroke変数として保存され、ポジショニングに使用されます。このコードは、パルスをカウントするのではなく、電圧を位置にマッピングすることにより、ポテンショメータフィードバックを処理するように変更できます。

このコードスニペット呼び出し このブロックに含まれていない追加の関数。

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()関数はです 本体 あなたのarduinoコードの。ループ()関数内で記述されたものはすべて、プログラム中に繰り返し実行されます。

プログラマー注: 個人的には、ループ機能を可能な限りシンプルに保つのが最も簡単だと思います。これはコードの一部です 他のほとんどの機能 コードで、そして できません コードの残りの部分なしで持ち上げられます。

このループ関数では、プログラムは入力のシリアルモニターをチェックし、コマンドでターゲット位置を更新し、動き関数を呼び出します。 PLCがシリアルモニターに送信するメッセージのほとんどは、このコードスニペットから届きます。

があります コメントの行がコメントアウトされました 以下 - 含まれている場合、このコードラインはアクチュエータへの0-100の入力をマッピングします。すなわち現在、あなたの入力はアクチュエータのストロークの割合になります。この行は、同様のマッピング形式で他の入力を利用するように変更することもできます。

このコードスニペットは、このブロックに含まれていない追加の関数を呼び出します。

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

 

動き

動き関数は、ターゲット位置に基づいてアクチュエータの動きの方向を制御します。これは、このプログラムの唯一の機能であり、モータードライバーにアクチュエーターを移動するように指示します。 

このコードスニペットは、このブロックに含まれていない追加の関数を呼び出します。

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

完全なコード

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