Fungsi Kontrol Serial untuk Aktuator Umpan Balik

Memprogram PLC untuk mengendalikan aktuator Anda dapat menjadi salah satu proyek yang lebih sulit untuk dilakukan. Dibutuhkan coba -coba, pengujian dan tumpukan kesabaran; meskipun hasilnya bisa sangat fungsional dan bermanfaat.

Kode dalam tutorial ini adalah program lengkap untuk fungsional Aktuator responsif serial. Memanfaatkan monitor serial dengan PLC Anda akan memungkinkan Anda untuk menghubungkan sistem Arduino Anda dengan komputer, modul atau sistem otomatisasi lain.

Kami akan meninjau setiap fungsi dan bagian kode saat kami pergi, sehingga Anda dapat menarik fungsi tertentu dari tutorial ini. Harap dicatat, beberapa fungsi memanggil fungsi lain yang tidak termasuk dalam blok kode yang sama, jadi Anda perlu memeriksa kode Anda untuk memastikannya akan dijalankan dengan benar.

Kode lengkap akan diposting di akhir artikel ini. Jika Anda ingin menggunakan kode lengkap, salin dan tempel ke perangkat lunak IDE Anda.

Tinjauan Program

Saat diinisialisasi, program ini akan pulang dan mengkalibrasi aktuator Anda, menemukan ujung gerak untuk unit. Kemudian menggerakkan aktuator ke titik tengah stroke untuk menunggu perintah lebih lanjut. Anda kemudian dapat memasukkan angka ke monitor serial Anda (dari PC Anda) dan aktuator akan pindah ke posisi itu. Program ini tidak bingung dengan penutupan akhir stroke, dan bekerja dengan sensor efek Hall atau aktuator sensor optik.

Daftar Bagian

Komponen dengan (*) termasuk dalam Arduino Starter Kit

Fungsi

Ringkasan fungsi

  1. void setup(): Menginisialisasi pin, memulai komunikasi serial, dan menjalankan rutinitas homing dan kalibrasi.
  2. void homingRoutine(): Memulai homing, memindahkan aktuator ke retraksi penuh, dan menetapkan stroke minimum.
  3. void calibrateActuator(): Memulai kalibrasi, memindahkan aktuator ke ekstensi penuh, dan menetapkan stroke maksimum.
  4. void loop(): Memeriksa input serial, memperbarui posisi target, dan mengontrol gerakan aktuator.
  5. void movement(): Mengontrol arah gerakan aktuator berdasarkan posisi target.
  6. void readSensor(): Membaca nilai sensor, pembaruan posisi, dan mencetak bacaan sensor.
  7. void stopMotor(): Menghentikan gerakan aktuator.
  8. bool isEndOfStroke(): Memeriksa akhir kondisi stroke dan menangani batas waktu.

Variabel

Variabel dalam kode Anda harus dipanggil sebelum digunakan. Praktik pemrograman terbaik adalah menetapkan dan mengatur variabel Anda di bagian atas kode Anda, untuk membuat modifikasi atau 'menyetel' variabel Anda lebih mudah.

Ini adalah variabel yang digunakan untuk kode ini, dengan komentar yang menjelaskan fungsinya dan rentang yang mungkin.

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

Pengaturan/Inisialisasi

Setup void (); Fungsi adalah fungsi dasar Arduino yang menginisialisasi PLC, memulai monitor serial, dan memberikan input dan output seperti yang diprogram.

Fungsi pengaturan ini memberikan 4 pin sebagai input atau output, kemudian menjalankan rutinitas homing dan kalibrasi.

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

  homingRoutine();
  calibrateActuator();
}

Rutinitas homing

Cuplikan kode ini adalah fungsi untuk menganut aktuator umpan balik Anda. Kode ini akan menarik kembali aktuator Anda sampai akhir stroke terdeteksi, dan akan menetapkan posisi itu nilai "0" - maka ia menginisialisasi fungsi kalibrasi.

Dalam program lengkap, fungsi homing dan kalibrasi dijalankan sekali, selama startup, dan tidak dipanggil lagi.

Panggilan Cuplikan Kode ini Fungsi tambahan yang tidak termasuk dalam blok ini.

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

Rutinitas kalibrasi

Selanjutnya, kami memiliki rutinitas kalibrasi kami. Fungsi ini akan sepenuhnya memperluas aktuator Anda setelah fungsi homing telah sepenuhnya menarik unit. Tujuan dari rutinitas ini adalah untuk menghitung pulsa sensor dari satu ujung stroke aktuator ke yang lain. Nilai ini kemudian disimpan sebagai variabel maxstroke dan digunakan untuk penentuan posisi. Kode ini dapat dimodifikasi untuk memproses umpan balik potensiometer dengan memetakan tegangan ke posisi, daripada menghitung pulsa.

Panggilan Cuplikan Kode ini Fungsi tambahan yang tidak termasuk dalam blok ini.

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

 

Lingkaran

Fungsi loop void () adalah tubuh utama Kode Arduino Anda. Apa pun yang ditulis dalam fungsi loop () akan dieksekusi berulang kali selama program.

Catatan pemrogram: Saya pribadi merasa paling mudah untuk menjaga fungsi loop sesederhana mungkin. Ini adalah bagian dari kode yang akan menelepon kebanyakan fungsi lainnya dalam kode, dan tidak bisa diangkat tanpa sisa kode.

Dalam fungsi loop ini, program memeriksa monitor serial untuk input, memperbarui posisi target dengan perintah Anda, dan memanggil fungsi gerakan. Sebagian besar pesan yang dikirim PLC ke monitor serial berasal dari cuplikan kode ini.

Ada baris kode dikomentari Di bawah ini - ketika dimasukkan, baris kode ini memetakan input 0-100 ke aktuator. Yaitu. Masukan Anda sekarang merupakan persentase dari stroke aktuator. Baris ini juga dapat dimodifikasi untuk menggunakan input lain dalam format yang dipetakan serupa.

Snippet kode ini memanggil fungsi tambahan yang tidak termasuk dalam blok ini.

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

 

Pergerakan

Fungsi gerakan mengontrol arah gerakan aktuator berdasarkan posisi target. Ini adalah satu -satunya fungsi dalam program ini yang memberitahu pengemudi motor untuk memindahkan aktuator. 

Snippet kode ini memanggil fungsi tambahan yang tidak termasuk dalam blok ini.

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 Baca

Fungsi pemrosesan sensor membaca nilai sensor, memperbarui posisi, dan mencetak pembacaan sensor ke monitor serial. Perintah serial dapat digunakan untuk debugging, atau dikomentari untuk pembacaan yang kurang sibuk.

Cuplikan kode ini dapat digunakan dalam program apa pun dan akan memberikan pembacaan pulsa yang akurat dari sensor umpan balik.

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

Berhenti motorik dan penonaktifan

Menghentikan gerakan aktuator dan mengaktifkan kembali unit untuk membaca monitor serial untuk perintah lebih lanjut. Ini adalah satu -satunya cuplikan kode dalam program ini yang akan menghentikan mosi aktuator.

Cuplikan kode ini dapat digunakan dalam program apa pun dengan aktuator apa pun, karena hanya mematikan motor dan mengubah keadaan 'aktif'.

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

Akhir pemeriksaan stroke

Periksa akhir kondisi stroke dan menangani batas waktu. Ketika aktuator mencapai ujung stroke dan berhenti bergerak, fungsi ini akan memicu dan mengatur ulang aktuator untuk input perintah baru, bahkan jika nomor target belum tercapai.

Panggilan Cuplikan Kode ini Fungsi tambahan yang tidak termasuk dalam blok ini.

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

Kode penuh

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