توابع کنترل سریال برای محرک های بازخورد

برنامه نویسی یک PLC برای کنترل محرک شما می تواند یکی از پروژه های دشوارتر برای انجام آن باشد. نیاز به آزمایش و خطا ، آزمایش و پشته صبر دارد. اگرچه نتایج می توانند فوق العاده کاربردی و با ارزش باشند.

کد موجود در این آموزش یک برنامه کامل برای یک کاربردی است محرک پاسخگو سریالبشر استفاده از مانیتور سریال با PLC خود به شما امکان می دهد سیستم Arduino خود را با سایر رایانه ها ، ماژول ها یا سیستم های اتوماسیون رابط کنید.

ما هر عملکرد و بخش کد را به عنوان می خواهیم مرور خواهیم کرد ، بنابراین ممکن است توابع خاص را از این آموزش بیرون بیاورید. لطفاً توجه داشته باشید ، برخی از کارکردها با سایر کارکردهایی که در همان بلوک کد گنجانده نشده اند فراخوانی می کنند ، بنابراین برای اطمینان از اجرای صحیح ، باید کد خود را بررسی کنید.

کد کامل در پایان این مقاله ارسال می شود. اگر مایل به استفاده از کد کامل هستید ، آن را در نرم افزار IDE خود کپی و چسبانده اید.

نمای کلی برنامه

با شروع اولیه ، این برنامه به خانه می رود و محرک های شما را کالیبره می کند و انتهای حرکت را برای واحد پیدا می کند. سپس محرک را به نقطه میانی سکته مغزی منتقل می کند تا منتظر دستورات بیشتر باشد. سپس می توانید یک شماره را در مانیتور سریال خود (از رایانه شخصی خود) وارد کنید و محرک به آن موقعیت منتقل می شود. این برنامه با خاموش شدن پایان سکته مغزی سردرگم نمی شود و با هر سنسور اثر سالن یا محرک سنسور نوری کار می کند.

لیست قطعات

مؤلفه های دارای (*) در کیت استارت آردوینو

توابع

خلاصه توابع

  1. void setup(): پین ها را اولیه می کند ، ارتباطات سریال را شروع می کند و روال Homing و Calibration را اجرا می کند.
  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

راه اندازی/اولیه سازی

تنظیم باطل () ؛ تابع یک تابع Arduino پایه است که PLC را آغاز می کند ، مانیتور سریال را شروع می کند و ورودی ها و خروجی ها را به صورت برنامه ریزی اختصاص می دهد.

این تابع تنظیم 4 پین را به عنوان ورودی یا خروجی اختصاص می دهد ، سپس روال Homing و Calibration را اجرا می کند.

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

روال روال

بعد ، ما روال کالیبراسیون خود را داریم. این عملکرد بعد از اینکه عملکرد Homing به طور کامل واحد را جمع کرد ، محرک شما را به طور کامل گسترش می دهد. هدف از این روال شمارش پالس های سنسور از یک انتهای سکته مغزی محرک به طرف دیگر است. سپس این مقدار به عنوان متغیر 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: