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
- Arduino plc (Uno* atau Mega 2560)
- Pengemudi motor (AD-MD6321 saat ini) - 1 per aktuator.
- Catu daya 12V untuk aktuator (melebihi undian amperage kumulatif)
- 1 papan tempat memotong roti, sesuai kebutuhan*
- Kabel jumper untuk Arduino Plc - Setiap MD saat ini akan membutuhkan 6 Koneksi wanita.
- Kawat 1-pin untuk PLC* (M-F 10pc/pk)
- Jumper Wire Kit (M-M, 75pc/pk; berbagai panjang);
- Aktuator dengan sensor umpan balik dan braket pemasangan aktuator, sesuai kebutuhan. (Sensor efek Hall atau aktuator sensor optik saja, untuk kode ini)
Fungsi
Ringkasan fungsi
-
void setup()
: Menginisialisasi pin, memulai komunikasi serial, dan menjalankan rutinitas homing dan kalibrasi. -
void homingRoutine()
: Memulai homing, memindahkan aktuator ke retraksi penuh, dan menetapkan stroke minimum. -
void calibrateActuator()
: Memulai kalibrasi, memindahkan aktuator ke ekstensi penuh, dan menetapkan stroke maksimum. -
void loop()
: Memeriksa input serial, memperbarui posisi target, dan mengontrol gerakan aktuator. -
void movement()
: Mengontrol arah gerakan aktuator berdasarkan posisi target. -
void readSensor()
: Membaca nilai sensor, pembaruan posisi, dan mencetak bacaan sensor. -
void stopMotor()
: Menghentikan gerakan aktuator. -
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;
}