আপনার অ্যাকিউউটারকে নিয়ন্ত্রণ করতে পিএলসি প্রোগ্রামিং করা আরও কঠিন প্রকল্পগুলির মধ্যে একটি হতে পারে। এটির জন্য ট্রায়াল এবং ত্রুটি, পরীক্ষা এবং ধৈর্য্যের একটি স্তূপ প্রয়োজন; যদিও ফলাফলগুলি অবিশ্বাস্যভাবে কার্যকরী এবং ফলপ্রসূ হতে পারে।
এই টিউটোরিয়ালের কোডটি একটি কার্যকরী জন্য একটি সম্পূর্ণ প্রোগ্রাম সিরিয়াল প্রতিক্রিয়াশীল অ্যাকুয়েটর। আপনার পিএলসির সাথে সিরিয়াল মনিটরটি ব্যবহার করা আপনাকে অন্যান্য কম্পিউটার, মডিউল বা অটোমেশন সিস্টেমের সাথে আপনার আরডুইনো সিস্টেমকে ইন্টারফেস করার অনুমতি দেবে।
আমরা যাওয়ার সাথে সাথে কোডের প্রতিটি ফাংশন এবং বিভাগটি পর্যালোচনা করব, যাতে আপনি এই টিউটোরিয়াল থেকে নির্দিষ্ট ফাংশনগুলি টানতে পারেন। দয়া করে নোট করুন, কিছু ফাংশন অন্যান্য ফাংশনগুলিতে কল করে যা একই কোড ব্লকে অন্তর্ভুক্ত নয়, তাই এটি সঠিকভাবে কার্যকর হবে তা নিশ্চিত করার জন্য আপনাকে আপনার কোডটি পরীক্ষা করতে হবে।
পুরো কোডটি এই নিবন্ধের শেষে পোস্ট করা হবে। আপনি যদি সম্পূর্ণ কোডটি ব্যবহার করতে চান তবে এটি আপনার আইডিই সফ্টওয়্যারটিতে অনুলিপি করুন এবং আটকান।
প্রোগ্রাম ওভারভিউ
যখন আরম্ভ করা হয়, এই প্রোগ্রামটি ইউনিটের জন্য গতির শেষগুলি সন্ধান করে আপনার অ্যাকিউইটরেটরগুলি বাড়িতে এবং ক্রমাঙ্কন করবে। এরপরে এটি অ্যাকুয়েটরটিকে স্ট্রোকের মাঝের পয়েন্টে আরও কমান্ডের জন্য অপেক্ষা করতে সরিয়ে দেয়। তারপরে আপনি আপনার সিরিয়াল মনিটরে একটি নম্বর ইনপুট করতে পারেন (আপনার পিসি থেকে) এবং অ্যাকিউউটর সেই অবস্থানে চলে যাবে। এই প্রোগ্রামটি স্ট্রোকের শেষের শাটফের মাধ্যমে বিভ্রান্ত হয় না এবং কোনও হল এফেক্ট সেন্সর বা অপটিক্যাল সেন্সর অ্যাকুয়েটরের সাথে কাজ করে।
অংশ তালিকা
এ (*) সহ উপাদানগুলি অন্তর্ভুক্ত করা হয় আরডুইনো স্টার্টার কিট
- আরডুইনো পিএলসি (ইউএনও* বা মেগা 2560)
- মোটর ড্রাইভার (উচ্চ বর্তমান AD-MD6321) - প্রতি অ্যাকুয়েটর প্রতি 1।
- 12 ভি পাওয়ার সাপ্লাই অ্যাকিউইটরেটরদের জন্য (ক্রমবর্ধমান অ্যাম্পেরেজ অঙ্কন অতিক্রম)
- 1 ব্রেডবোর্ড, প্রয়োজন হিসাবে*
- আরডুইনো পিএলসির জন্য জাম্পার তারগুলি - প্রতিটি উচ্চ বর্তমান এমডি প্রয়োজন 6 মহিলা সংযোগ।
- পিএলসিএসের জন্য 1-পিন ওয়্যার* (এম-এফ 10 পিসি/পিকে)
- জাম্পার ওয়্যার কিট (এম-এম, 75 পিসি/পিকে; বিভিন্ন দৈর্ঘ্য);
- প্রতিক্রিয়া সেন্সর সহ অ্যাকিউটিউটর এবং অ্যাকুয়েটর মাউন্টিং বন্ধনী, প্রয়োজন হিসাবে। (এই কোডের জন্য হল এফেক্ট সেন্সর বা অপটিক্যাল সেন্সর অ্যাকিউটিউটরগুলি কেবল)
ফাংশন
ফাংশন সংক্ষিপ্তসার
-
void setup()
: পিনগুলি আরম্ভ করে, সিরিয়াল যোগাযোগ শুরু করে এবং হোমিং এবং ক্রমাঙ্কন রুটিনগুলি চালায়। -
void homingRoutine()
: হোমিং শুরু করে, অ্যাকিউউটারকে সম্পূর্ণ প্রত্যাহার করে তোলে এবং ন্যূনতম স্ট্রোক সেট করে। -
void calibrateActuator()
: ক্রমাঙ্কন শুরু করে, অ্যাকিউউটারকে সম্পূর্ণ এক্সটেনশনে নিয়ে যায় এবং সর্বাধিক স্ট্রোক সেট করে। -
void loop()
: সিরিয়াল ইনপুট জন্য চেক, লক্ষ্য অবস্থান আপডেট করে এবং অ্যাকুয়েটর আন্দোলন নিয়ন্ত্রণ করে। -
void movement()
: লক্ষ্য অবস্থানের উপর ভিত্তি করে অ্যাকুয়েটর আন্দোলনের দিকটি নিয়ন্ত্রণ করে। -
void readSensor()
: সেন্সর মানগুলি, আপডেটের অবস্থান এবং সেন্সর রিডিংগুলি প্রিন্ট করে। -
void stopMotor()
: অ্যাকুয়েটর আন্দোলন বন্ধ করে দেয়। -
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
সেটআপ/সূচনা
শূন্য সেটআপ (); ফাংশন হ'ল একটি বেস আরডুইনো ফাংশন যা পিএলসি শুরু করে, সিরিয়াল মনিটর শুরু করে এবং প্রোগ্রাম হিসাবে ইনপুট এবং আউটপুটগুলিকে বরাদ্দ করে।
এই সেটআপ ফাংশন 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");
}
ক্রমাঙ্কন রুটিন
এরপরে, আমাদের আমাদের ক্রমাঙ্কন রুটিন রয়েছে। হোমিং ফাংশনটি ইউনিটটি পুরোপুরি প্রত্যাহার করার পরে এই ফাংশনটি আপনার অ্যাকিউউটারকে পুরোপুরি প্রসারিত করবে। এই রুটিনের উদ্দেশ্য হ'ল সেন্সর ডালগুলি অন্যদিকে অ্যাকিউউটরের স্ট্রোকের এক প্রান্ত থেকে গণনা করা। এই মানটি তখন ম্যাক্সস্ট্রোক ভেরিয়েবল হিসাবে সংরক্ষণ করা হয় এবং অবস্থানের জন্য ব্যবহৃত হয়। এই কোডটি ডাল গণনা না করে ভোল্টেজকে ম্যাপিং করে অবস্থানের মাধ্যমে পেন্টিওমিটার প্রতিক্রিয়া প্রক্রিয়া করতে সংশোধন করা যেতে পারে।
এই কোড স্নিপেট কল অতিরিক্ত ফাংশন (গুলি) যা এই ব্লকের অন্তর্ভুক্ত নয়।
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;
}
}
}
লুপ
শূন্য লুপ () ফাংশনটি প্রধান দেহ আপনার আরডুইনো কোডের। লুপ () ফাংশনের মধ্যে লিখিত যে কোনও কিছু প্রোগ্রামের সময় বারবার কার্যকর করা হবে।
প্রোগ্রামার দ্রষ্টব্য: আমি ব্যক্তিগতভাবে লুপ ফাংশনটিকে যতটা সম্ভব সহজ রাখা সহজ মনে করি। এটি কোডের অংশ যা কল করবে বেশিরভাগ অন্যান্য ফাংশন কোডে, এবং পারে না বাকি কোড ছাড়াই উত্তোলন করা।
এই লুপ ফাংশনে, প্রোগ্রামটি ইনপুটটির জন্য সিরিয়াল মনিটরের জন্য পরীক্ষা করে, আপনার কমান্ডের সাথে লক্ষ্য অবস্থান আপডেট করে এবং আন্দোলনের ফাংশনটিকে কল করে। পিএলসি সিরিয়াল মনিটরে প্রেরণ করে এমন বেশিরভাগ বার্তা এই কোড স্নিপেট থেকে আসে।
একটি আছে কোডের লাইন মন্তব্য করেছে নীচে - যখন অন্তর্ভুক্ত থাকে, কোডের এই লাইনটি অ্যাকিউউটরের কাছে 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;
}