Chức năng điều khiển nối tiếp cho bộ truyền động phản hồi

Lập trình PLC để kiểm soát bộ truyền động của bạn có thể là một trong những dự án khó thực hiện hơn. Nó yêu cầu thử nghiệm và lỗi, thử nghiệm và một đống kiên nhẫn; Mặc dù kết quả có thể vô cùng chức năng và bổ ích.

Mã trong hướng dẫn này là một chương trình hoàn chỉnh cho một chức năng Bộ truyền động đáp ứng nối tiếp. Sử dụng màn hình nối tiếp với PLC của bạn sẽ cho phép bạn giao tiếp với hệ thống Arduino của mình với các máy tính, mô -đun hoặc hệ thống tự động hóa khác.

Chúng tôi sẽ xem xét từng chức năng và phần của mã khi chúng tôi đi, vì vậy bạn có thể rút các chức năng cụ thể ra khỏi hướng dẫn này. Xin lưu ý, một số chức năng gọi các chức năng khác không được bao gồm trong cùng một khối mã, vì vậy bạn sẽ cần kiểm tra mã của mình để đảm bảo nó sẽ thực thi đúng.

Mã đầy đủ sẽ được đăng ở cuối bài viết này. Nếu bạn muốn sử dụng mã đầy đủ, sao chép và dán nó vào phần mềm IDE của bạn.

Tổng quan về chương trình

Khi được khởi tạo, chương trình này sẽ về nhà và hiệu chỉnh các bộ truyền động của bạn, tìm kết thúc chuyển động cho thiết bị. Sau đó, nó di chuyển bộ truyền động đến điểm giữa của đột quỵ để chờ thêm các lệnh. Sau đó, bạn có thể nhập một số vào màn hình nối tiếp của bạn (từ PC) và bộ truyền động sẽ di chuyển đến vị trí đó. Chương trình này không bị nhầm lẫn bởi sự ngắt cuối cùng và hoạt động với bất kỳ cảm biến hiệu ứng Hall hoặc bộ truyền động cảm biến quang nào.

Danh sách bộ phận

Các thành phần có (*) được bao gồm trong Bộ khởi động Arduino

Chức năng

Tóm tắt các chức năng

  1. void setup(): Khởi tạo các chân, bắt đầu giao tiếp nối tiếp và chạy các thói quen hiệu chuẩn và hiệu chuẩn.
  2. void homingRoutine(): Bắt đầu homing, di chuyển bộ truyền động đến rút lại đầy đủ và đặt đột quỵ tối thiểu.
  3. void calibrateActuator(): Bắt đầu hiệu chuẩn, di chuyển bộ truyền động sang mở rộng đầy đủ và đặt đột quỵ tối đa.
  4. void loop(): Kiểm tra đầu vào nối tiếp, cập nhật vị trí mục tiêu và kiểm soát chuyển động của bộ truyền động.
  5. void movement(): Kiểm soát hướng chuyển động của bộ truyền động dựa trên vị trí mục tiêu.
  6. void readSensor(): Đọc các giá trị cảm biến, cập nhật vị trí và in các bài đọc cảm biến.
  7. void stopMotor(): Dừng phong trào truyền động.
  8. bool isEndOfStroke(): Kiểm tra kết thúc của các điều kiện đột quỵ và xử lý thời gian chờ.

Biến

Các biến trong mã của bạn phải được gọi trước khi chúng được sử dụng. Thực hành lập trình tốt nhất là gán và đặt các biến của bạn ở đầu mã của bạn, để làm cho sửa đổi hoặc 'điều chỉnh' các biến của bạn dễ dàng hơn.

Đây là những biến được sử dụng cho mã này, với một nhận xét giải thích chức năng của chúng và phạm vi có thể.

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

Thiết lập/khởi tạo

Thiết lập khoảng trống (); Chức năng là một hàm Arduino cơ sở khởi tạo PLC, bắt đầu màn hình nối tiếp và gán các đầu vào và đầu ra như được lập trình.

Hàm thiết lập này gán 4 chân làm đầu vào hoặc đầu ra, sau đó chạy các thói quen hiệu chuẩn và homing.

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

  homingRoutine();
  calibrateActuator();
}

Thói quen homing

Đoạn mã này là chức năng để dẫn các bộ truyền động phản hồi của bạn. Mã này sẽ rút lại bộ truyền động của bạn cho đến khi kết thúc đột quỵ và sẽ gán vị trí đó một giá trị "0" - sau đó nó khởi tạo chức năng hiệu chuẩn.

Trong chương trình đầy đủ, các chức năng Homing và Hiệu chỉnh được chạy một lần, trong khi khởi động và không được gọi lại.

CNIPPET mã này gọi Chức năng bổ sung không được bao gồm trong khối này.

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

Hiệu chuẩn thói quen

Tiếp theo, chúng tôi có thói quen hiệu chuẩn của chúng tôi. Chức năng này sẽ mở rộng hoàn toàn bộ truyền động của bạn sau khi chức năng homing đã rút lại hoàn toàn đơn vị. Mục đích của thói quen này là để đếm các xung cảm biến từ một đầu của hành trình truyền động sang đầu kia. Giá trị này sau đó được lưu dưới dạng biến MaxStroke và được sử dụng để định vị. Mã này có thể được sửa đổi để xử lý phản hồi chiết áp bằng cách ánh xạ điện áp đến vị trí, thay vì đếm các xung.

CNIPPET mã này gọi Chức năng bổ sung không được bao gồm trong khối này.

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

 

Vòng lặp

Hàm khoảng trống () là cơ thể chính của mã Arduino của bạn. Bất cứ điều gì được viết trong hàm loop () sẽ được thực thi nhiều lần trong chương trình.

Lập trình viên Lưu ý: Cá nhân tôi thấy nó dễ dàng nhất để giữ chức năng vòng lặp đơn giản nhất có thể. Đây là một phần của mã sẽ gọi Hầu hết các chức năng khác trong mã và không thể được nâng lên mà không có phần còn lại của mã.

Trong chức năng vòng lặp này, chương trình kiểm tra màn hình nối tiếp cho đầu vào, cập nhật vị trí mục tiêu bằng lệnh của bạn và gọi chức năng chuyển động. Hầu hết các tin nhắn mà PLC gửi đến màn hình nối tiếp đến từ đoạn mã này.

Có a Dòng mã được nhận xét Dưới đây - khi được bao gồm, dòng mã này ánh xạ đầu vào 0-100 cho bộ truyền động. Tức là Đầu vào của bạn bây giờ là một tỷ lệ phần trăm của động cơ của bộ truyền động. Dòng này cũng có thể được sửa đổi để sử dụng các đầu vào khác trong một định dạng được ánh xạ tương tự.

Mã mã này gọi (các) hàm bổ sung không được bao gồm trong khối này.

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

 

Sự chuyển động

Hàm chuyển động kiểm soát hướng chuyển động của bộ truyền động dựa trên vị trí mục tiêu. Đây là chức năng duy nhất trong chương trình này bảo người lái xe máy di chuyển bộ truyền động. 

Mã mã này gọi (các) hàm bổ sung không được bao gồm trong khối này.

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

Cảm biến đọc

Hàm xử lý cảm biến đọc các giá trị cảm biến, cập nhật vị trí và in các bài đọc cảm biến vào màn hình nối tiếp. Các lệnh nối tiếp có thể được sử dụng để gỡ lỗi, hoặc nhận xét về việc đọc ít bận rộn hơn.

Đoạn mã này có thể được sử dụng trong bất kỳ chương trình nào và sẽ cung cấp một cách đọc chính xác các xung từ cảm biến phản hồi.

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

Dừng động cơ và ngừng hoạt động

Dừng chuyển động của bộ truyền động và kích hoạt lại thiết bị để đọc màn hình nối tiếp cho các lệnh tiếp theo. Đây là đoạn mã duy nhất trong chương trình này sẽ ngăn chặn chuyển động của bộ truyền động.

Đoạn mã này có thể được sử dụng trong bất kỳ chương trình nào với bất kỳ bộ truyền động nào, vì nó chỉ tắt động cơ và thay đổi trạng thái 'hoạt động'.

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

Kết thúc kiểm tra đột quỵ

Kiểm tra kết thúc của các điều kiện đột quỵ và xử lý thời gian chờ. Khi bộ truyền động chạm vào cuối đột quỵ và ngừng di chuyển, chức năng này sẽ kích hoạt và đặt lại bộ truyền động cho các đầu vào lệnh mới, ngay cả khi số mục tiêu chưa đạt được.

CNIPPET mã này gọi Chức năng bổ sung không được bao gồm trong khối này.

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

Mã đầy đủ

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