Aktüatörünüzü kontrol etmek için bir PLC programlamak, üstlenecek daha zor projelerden biri olabilir. Deneme yanılma, test ve sabır yığını gerektirir; Her ne kadar sonuçlar inanılmaz işlevsel ve ödüllendirici olabilir.
Bu öğreticideki kod, işlevsel bir programdır Seri duyarlı aktüatör. Seri monitörü PLC'nizle kullanmak, Arduino sisteminizi diğer bilgisayarlar, modüller veya otomasyon sistemleriyle arayüz etmenize izin verecektir.
Kodun her bir işlevini ve bölümünü giderken inceleyeceğiz, böylece belirli işlevleri bu öğreticiden çıkarabilirsiniz. Lütfen, bazı işlevlerin aynı kod bloğuna dahil olmayan diğer işlevleri çağırdığını, bu nedenle düzgün bir şekilde yürütüleceğinden emin olmak için kodunuzu kontrol etmeniz gerekeceğini unutmayın.
Tam kod bu makalenin sonunda yayınlanacaktır. Tam kodu kullanmak istiyorsanız, kopyalayıp IDE yazılımınıza yapıştırın.
Programa Genel Bakış
Başlatıldığında, bu program aktüatörlerinizi ev sahipliği yapacak ve kalibre edecek ve ünite için hareketin uçlarını bulacaktır. Daha sonra aktüatörü daha fazla komut beklemek için inme orta noktasına taşır. Daha sonra seri monitörünüze (PC'nizden) bir sayı girebilirsiniz ve aktüatör bu konuma geçecektir. Bu program inme sonu kapatma ile karıştırılmaz ve herhangi bir Hall efekt sensörü veya optik sensör aktüatörü ile çalışır.
Parça Listesi
(*) Olan bileşenler Arduino başlangıç kiti
- Arduino plc (Uno* veya Mega 2560)
- Motorlu sürücü (Yüksek Mevcut AD-MD6321) - aktüatör başına 1.
- 12V güç kaynağı Aktüatörler için (kümülatif amper çekilişini aşın)
- 1 breadboard, gerektiği gibi*
- Arduino plc için jumper telleri - Her yüksek akım MD 6 Kadın bağlantıları.
- PLC'ler için 1 pimli tel* (M-F 10pc/PK)
- Jumper tel kiti (M-M, 75pc/PK; çeşitli uzunluklar);
- Geri bildirim sensörleri olan aktüatörler ve gerektiğinde aktüatör montaj braketleri. (Bu kod için sadece salon efekt sensörü veya optik sensör aktüatörleri)
İşlevler
İşlevlerin özeti
-
void setup()
: Pimleri başlatır, seri iletişimi başlatır ve homing ve kalibrasyon rutinlerini çalıştırır. -
void homingRoutine()
: Homing'i başlatır, aktüatörü tam geri çekilmeye hareket ettirir ve minimum stroku ayarlar. -
void calibrateActuator()
: Kalibrasyonu başlatır, aktüatörü tam uzantıya taşır ve maksimum stroku ayarlar. -
void loop()
: Seri girişini kontrol eder, hedef konumu günceller ve aktüatör hareketini kontrol eder. -
void movement()
: Hedef konuma göre aktüatör hareketinin yönünü kontrol eder. -
void readSensor()
: Sensör değerlerini okur, konumu günceller ve sensör okumalarını yazdırır. -
void stopMotor()
: Aktüatör hareketini durdurur. -
bool isEndOfStroke()
: İnme koşullarının sonunu kontrol eder ve zaman aşımlarını işler.
Değişkenler
Kodunuzdaki değişkenler kullanılmadan önce çağrılmalıdır. En iyi programlama uygulaması, değişkenlerinizi kodunuzun üstüne atamak ve ayarlamak, değişkenlerinizi daha kolay değiştirme veya 'ayarlama' yapmaktır.
Bunlar, işlevlerini ve olası aralığını açıklayan bir yorum ile bu kod için kullanılan değişkenlerdir.
//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
Kurulum/Başlatma
Boşluk kurulumu (); Fonksiyon, PLC'yi başlatan, seri monitör başlatan ve programlanmış olarak giriş ve çıkışlar atayan bir temel Arduino işlevidir.
Bu kurulum işlevi 4 pim giriş veya çıkış olarak atar, ardından homing ve kalibrasyon rutinlerini çalıştırır.
void setup() {
pinMode(Xpin, OUTPUT);
pinMode(Rpin, OUTPUT);
pinMode(sensorPin, INPUT_PULLUP);
pinMode(sensorPin2, INPUT_PULLUP);
Serial.begin(115200);
homingRoutine();
calibrateActuator();
}
Homing Rutini
Bu kod snippet, geri bildirim aktüatörlerinizi kullanma işlevidir. Bu kod, vuruşun sonu algılanana kadar aktüatörünüzü geri çekecektir ve bu pozisyonu "0" değeri atar - sonra kalibrasyon fonksiyonunu başlatır.
Tam programda, homing ve kalibrasyon fonksiyonları başlangıç sırasında bir kez çalıştırılır ve tekrar çağrılmaz.
Bu kod snippet çağırıyor Bu bloğa dahil olmayan ek fonksiyonlar.
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");
}
Kalibrasyon rutini
Sonra kalibrasyon rutinimiz var. Bu işlev, bir üniteyi tamamen geri çektikten sonra aktüatörünüzü tamamen genişletecektir. Bu rutinin amacı, sensör darbelerini aktüatörün vuruşunun bir ucundan diğerine saymaktır. Bu değer daha sonra MaxStroke değişkeni olarak kaydedilir ve konumlandırma için kullanılır. Bu kod, voltajı nabızları saymak yerine konuma eşleştirerek potansiyometre geri bildirimini işlemek için değiştirilebilir.
Bu kod snippet çağırıyor Bu bloğa dahil olmayan ek fonksiyonlar.
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;
}
}
}
Döngü
Boşluk döngüsü () işlevi ana gövde Arduino kodunuz. Loop () işlevinde yazılmış herhangi bir şey program sırasında tekrar tekrar yürütülecektir.
Programcılar Not: Şahsen döngü işlevini olabildiğince basit tutmayı en kolay buluyorum. Bu, kodun arayacak kısmı Diğer birçok işlev kodda ve yapamamak Kodun geri kalanı olmadan kaldırılacak.
Bu döngü işlevinde, program giriş için seri monitör kontrol eder, hedef konumunu komutunuzla günceller ve hareket işlevini çağırır. PLC'nin seri monitöre gönderdiği mesajların çoğu bu kod snippet'ten gelir.
Bir kod çizgisi yorumlandı Aşağıda - dahil edildiğinde, bu kod satırı aktüatöre 0-100 girişini eşler. Yani Girişiniz artık aktüatörün vuruşunun bir yüzdesidir. Bu çizgi, diğer girişleri benzer eşlenmiş bir formatta kullanacak şekilde de değiştirilebilir.
Bu kod snippet, bu bloğa dahil olmayan ek işlevleri çağırır.
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");
}
}
Hareket
Hareket fonksiyonu, hedef konuma göre aktüatör hareketinin yönünü kontrol eder. Bu programda motor sürücüsüne aktüatörü hareket ettirmesini söyleyen tek işlevdir.
Bu kod snippet, bu bloğa dahil olmayan ek işlevleri çağırır.
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
}
}
Sensör okundu
Sensör işleme işlevi sensör değerlerini okur, konumu günceller ve sensör okumalarını seri monitöre yazdırır. Seri komutları hata ayıklama için kullanılabilir veya daha az sürüngeli bir okuma için yorumlanabilir.
Bu kod snippet'i herhangi bir programda kullanılabilir ve bir geri bildirim sensöründen darbelerin doğru bir şekilde okunmasını sağlar.
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;
}
Motor durdurma ve deaktivasyon
Aktüatör hareketini durdurur ve üniteyi daha fazla komut için seri monitörü okumaya uygundur. Bu programda aktüatörün hareketini durduracak tek kod snippet'idir.
Bu kod snippet, herhangi bir aktüatörle herhangi bir programda kullanılabilir, çünkü motoru kapatır ve 'aktif' durumu değiştirir.
void stopMotor() {
if (active) {
active=false;
digitalWrite(Xpin,LOW);
digitalWrite(Rpin,LOW);
}
}
İnme Sonrası Kontrolü
İnme koşullarının sonunu kontrol eder ve zaman aşımlarını işler. Aktüatör inme sonuna çarptığında ve hareket etmeyi durdurduğunda, bu işlev, hedef sayıya henüz ulaşılmasa bile yeni komut girişleri için aktüatörü tetikleyecek ve sıfırlayacaktır.
Bu kod snippet çağırıyor Bu bloğa dahil olmayan ek fonksiyonlar.
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;
}
Tam kod
//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;
}