Bangun Aktuator Servo Linier Presisi dengan Umpan Balik Posisi – Panduan Langkah demi Langkah
Dalam tutorial ini kita akan mempelajari cara membuat aktuator servo linier. Tidak seperti aktuator linier biasa yang bergerak ke arah tertentu saat diberi tegangan, aktuator servo linier yang dibuat khusus ini memberikan gerakan yang presisi dan berulang sehingga dapat dikontrol dengan mudah.
Disebut aktuator servo karena dilengkapi sistem putaran umpan balik sehingga kita dapat mengontrol gerakan keluaran aktuator secara akurat.
Anda dapat menonton video berikut atau membaca tutorial tertulis di bawah ini.
Ikhtisar
Input untuk mengendalikan aktuator servo linier ini dapat berupa analog atau digital. Dalam hal input analog, dapat berupa potensiometer jenis apa pun seperti yang ditunjukkan di sini. Potensiometer linier, potensiometer putar biasa, atau misalnya joystick yang juga merupakan potensiometer putar, dan sebagainya.
Dalam hal input digital, kita dapat mengontrol aktuator dengan RC Transmitter. Tentunya untuk setup ini kita juga membutuhkan RC receiver yang berfungsi sebagai input ke aktuator.
Untuk mode masukan analog dan digital ini, kita hanya memerlukan 3 kabel untuk membuat sambungan, 2 di antaranya untuk memberi daya pada perangkat masukan, dan kabel ketiga untuk sinyal masukan.
Fitur keren yang dimiliki aktuator servo linier yang dibuat khusus ini adalah kita dapat mengatur posisi awal dan akhir khusus untuk batang keluaran serta menyesuaikan sensitivitas atau seberapa cepat aktuator akan merespons masukan kita.
Padahal, fitur favorit saya adalah kemampuan untuk mengontrol aktuator ini dari PC atau Laptop melalui komunikasi port serial. Kita dapat memasukkan nilai dalam satuan milimeter melalui monitor Serial Arduino IDE dan aktuator akan berpindah ke posisi tersebut.
Yang lebih kerennya lagi, kita bisa melakukan gerakan berulang-ulang, atau menyimpan posisi, dengan mengetikkan “save” pada serial monitor di setiap posisi yang kita inginkan, lalu menyuruh aktuator untuk mengulangi gerakan tersebut secara berulang, dengan mengetikkan “run” pada serial monitor.
Sekarang izinkan saya menjelaskan semua yang perlu Anda ketahui tentang aktuator servo linier yang dibuat khusus ini, cara kerjanya, dan cara saya mendesainnya, sehingga Anda juga dapat membuatnya sendiri.
Cara Kerjanya
Jadi, sistem kontrol loop tertutup didasarkan pada sensor posisi putar magnetik AS5600 dan kontrol PID yang diterapkan untuk menggerakkan motor DC.
Sebenarnya, saya menggunakan papan pengontrol motor servo khusus yang sama dengan yang saya buat di video sebelumnya, yang mencakup mikrokontrolernya sendiri dan yang lainnya untuk dengan mudah mengubah motor DC apa pun menjadi motor servo yang berdiri sendiri.
Anda dapat melihat tutorial tersebut untuk penjelasan rinci tentang cara kerja motor servo dan sistem kontrol loop tertutup.
Secara cepat, motor servo merupakan suatu sistem kendali loop tertutup dimana sinyal masukan atau posisi yang diinginkan dibandingkan dengan posisi motor sebenarnya yang kita peroleh dari sensor umpan balik posisi.
Perbedaan yang terjadi disebut dengan error, kemudian diproses pada pengontrol yang memerintahkan motor untuk bergerak hingga mencapai posisi yang diinginkan.
Jadi, aktuator servo linier ini memiliki prinsip kerja yang sama dengan motor servo, namun dengan satu langkah tambahan yaitu mengubah gerak putaran motor menjadi gerak linier dengan bantuan mekanisme lead screw.
Desain Aktuator Servo Linier
Berikut model 3D aktuator servo linier ini, dari situ kita dapat melihat cara kerja semuanya.
Sensor posisi putar magnetik AS5600 terletak di sisi belakang aktuator, dan memantau perputaran sekrup utama. Sekrup utama yang saya gunakan memiliki pitch 8mm, artinya, setiap putaran penuh, mur sekrup utama membuat gerakan linier 8mm.
AS5600 adalah encoder 12-bit yang berarti dapat menghasilkan 4096 posisi per putaran. Jika kita membagi 8 dengan 4096, kita mendapatkan resolusi 0,001953mm. Itu adalah perubahan posisi terkecil yang dapat dideteksi oleh encoder AS5600. Menurut saya, itu cukup mengesankan.
Motor DC yang saya gunakan adalah motor 12V dengan disertakan gearbox reduksi yang menghasilkan output 480 RPM. Jika kita membagi 480 dengan 60, kita mendapatkan nilai 8 putaran per detik, dan jika kita mengalikan angka tersebut dengan 8, karena sekrup utama memiliki pitch 8mm, kita mendapatkan kecepatan linier aktuator sebesar 64mm/s.
Menurut saya tepat, karena gerak maksimum batang aktuator ini adalah 150mm, sehingga akan memakan waktu sekitar 2,5 detik dari posisi awal hingga akhir pada kecepatan maksimum, atau sekitar 3 detik jika kita memasukkan akselerasi dan deselerasi. Oleh karena itu, saya menggunakan rasio gearset 1:1 untuk menggerakkan sekrup utama.
Desain seluruh aktuator linier didasarkan pada ukuran PCB pengontrol motor servo yang dibuat khusus dan tentu saja sekrup utama dan mur sekrup utama. PCB tersebut memiliki dimensi 40x40mm, sehingga merupakan ukuran minimum blok silinder.
Mur sekrup timah 8mm memiliki dimensi luar 22mm, jadi menurut itu saya merancang batangnya. Mur dan batang dihubungkan dengan empat baut M3 dan sisipan berulir. Di bagian atas batang terdapat bantalan yang dapat digeser pada blok silinder, yang digunakan untuk memandu batang dan mencegahnya berputar.
Pada tutup silinder keluaran, kami memiliki 4 bantalan kecil yang memandu batang keluar dari blok silinder.
Secara keseluruhan, menurut saya aktuator liniernya cukup kompak mengingat semua komponen yang digunakan.
Saya juga berhasil memasang saklar batas mikro di dalam blok silinder, yang digunakan untuk homing dan mengatur posisi awal aktuator.
Unduh Model 3D
Anda dapat melihat dan menjelajahi model 3D aktuator servo linier yang dibuat khusus ini langsung di browser web Anda dengan Onshape. (Anda memerlukan akun Onshape untuk itu, Anda dapat membuat akun gratis untuk digunakan di rumah)
Anda bisa mendapatkan file STL yang diperlukan untuk pencetakan 3D, serta file STEP model 3D ini dari Cults3D.
Hal lain yang perlu disebutkan di sini adalah Anda dapat dengan mudah meningkatkan panjang gerak maksimum aktuator linier ini, hanya dengan menambah panjang blok silinder dan batang. Saya memilih dimensi ini karena saya ingin semua bagian muat pada printer 3D dengan print bed lebih kecil yaitu 220x220mm. Bagian terbesar di sini adalah batangnya, yang panjangnya 215mm.
Pencetakan 3D
Creality Ender-3 V3 SE saya yang baru berhasil mencetaknya dengan baik dalam orientasi horizontal sepanjang sumbu Y. Meskipun kita perlu melakukan sedikit pengiriman, mencetak batang dalam orientasi ini akan berkontribusi pada pengoperasian yang lebih lancar dan batang yang lebih kuat.
Saat mencetak 3D, penting untuk menggunakan fitur Ekspansi Horizontal di perangkat lunak pengiris Anda untuk mengimbangi perluasan filamen dan mendapatkan bagian yang lebih akurat secara dimensi.
Saya menggunakan nilai –0,1mm, namun Anda harus melakukan beberapa tes cetakan untuk melihat nilai apa yang sesuai dengan printer 3D Anda.
Saya mencetak blok silinder sepanjang sumbu Z untuk menghindari pencetakan banyak bahan pendukung. Creality Ender-3 V3 SE juga melakukan tugasnya dengan baik untuk pencetakan ini.
Saya sangat terkejut dengan kualitas cetak yang ditawarkan printer 3D ini mengingat harganya. Sangat mudah untuk menyiapkan printer 3D, printer ini memiliki perataan alas otomatis, ekstruder langsung, kualitas cetak bagus, dan peningkatan kecepatan pencetakan hingga 250mm/s. Semua ini hanya dengan harga di bawah $200 menjadikannya salah satu printer 3D terbaik bagi mereka yang memiliki anggaran terbatas.
Lihat Printer 3D ini di toko Creality atau Amazon . Lihat juga ulasan mendetail saya di situs web saya.
Perakitan
Bagaimanapun, ini semua bagian cetakan 3D, jadi sekarang kita bisa mulai dengan merakit aktuator linier.
Daftar bagian
Anda bisa mendapatkan komponen-komponen yang dibutuhkan untuk proyek Linear Servo Actuator ini dari link di bawah ini:
Mekanis:
- Sekrup Utama 8mm Tr8x8 ………………………………………….. Amazon / AliExpress
- Bantalan bola 8x22x7mm………………………………………. Amazon / AliExpress
- Bantalan Bola 4x9x4mm x 4 ………………………………….. Amazon / AliExpress
- Bantalan bola 6x13x5mm 686-2RS x1 ……………..….. Amazon /AliExpress
- Sisipan berulir M3x5mm dan M4x5mm ……….. Amazon /AliExpress
- Baut dan mur M3 dan M4 ……….…………….…. Amazon /AliExpress
Baut:M3x8 – 10 buah; M3x10 – 2 buah; Countersink M3x10 – 1 buah; M4x6 – 2 buah; M4x25 – 2 buah; M4x30 – 2 buah; M2x8 – 6 buah; Sekrup grub M4x5 – 5 buah
Elektronik:
- Encoder magnetik AS5600 ………………….. Amazon / AliExpress
- Pengemudi motor DC DRV8871 ……….…. Amazon / AliExpress
- Atmega328p-AU …………………………………. Amazon / AliExpress
- Osilator kristal 16Mhz …………………….. Amazon / AliExpress
- AMS1117 Pengatur tegangan 5V………..…. Amazon / AliExpress
- Potensiometer persegi 3386P………………. Amazon / AliExpress
- Kapasitor 0805 Kit…………………………….…. Amazon / AliExpress
- Motor DC 12V – ~ 50RPM …………….……. Amazon /AliExpress
Pengungkapan:Ini adalah tautan afiliasi. Sebagai Rekanan Amazon, saya memperoleh penghasilan dari pembelian yang memenuhi syarat.
Merakit mekanisme sekrup utama
Pertama, kita perlu memasang sekrup utama pada tempatnya di blok dasar silinder. Untuk itu, pertama-tama kita perlu memasukkan mur cetakan 3D yang memiliki ulir yang sama dengan sekrup utama.
Agak sulit untuk mengencangkan mur ke sekrup utama karena sekrupnya sangat pas, tapi itulah yang kita perlukan di sini. Mur ini menahan seluruh gaya pada saat batang didorong, sehingga semakin kencang pasnya, semakin besar pula gaya yang mampu ditahan. Selain itu, mur juga memiliki lubang untuk memasukkan sisipan berulir untuk mengencangkannya ke poros dengan sekrup grub.
Sekrup utama dipasang pada blok dasar silinder dengan bantuan dua bantalan bola dengan diameter luar 22 mm.
Di sisi belakang terdapat roda gigi yang menggerakkan sekrup utama. Roda gigi ini juga memiliki ulir yang cocok dan dua lubang untuk sisipan berulir untuk mengencangkannya ke sekrup utama dengan sekrup grub.
Sambungan ini juga penting karena menyalurkan seluruh torsi motor ke sekrup utama, sehingga tidak boleh tergelincir.
Untuk membuat sub-rakitan ini, pertama-tama kita perlu memasang sisipan berulir pada roda gigi dan mur, serta beberapa pada blok silinder.
Kami mengencangkan roda gigi dan mur ke arah yang berlawanan tetapi tidak terlalu kencang karena ini menambah gaya aksial pada bantalan. Kemudian dengan menggunakan beberapa sekrup grub, kita dapat mengencangkan mur dan roda gigi ke sekrup utama.
Setelah diamankan, kita dapat melihat bahwa sekrup utama belum terpasang pada tempatnya. Kita perlu menambahkan pelat ini ke blok silinder yang akan memastikan bantalan akan tetap berada di tempatnya di blok silinder.
Ini melengkapi sub-perakitan ini; sekrup utama sekarang berdiri kokoh di tempatnya sementara dapat berputar bebas.
Selanjutnya kita siapkan batangnya. Batangnya berlubang sepanjang keseluruhannya untuk menampung sekrup utama. Untuk menyambungkan mur sekrup utama dan batang, pertama-tama kita perlu memasang beberapa sisipan berulir.
Di sisi atas batang, kita perlu memasang bantalan pemandu dengan diameter luar 13mm dan diameter dalam 6mm.
Kami menempatkan bantalan pada poros berongga 6 mm yang dicetak 3D dan mengencangkannya ke batang dengan sekrup countersunk M3 dengan panjang 10 mm. Batangnya sekarang sudah siap dan kita bisa melihat bagaimana batang itu akan meluncur di rel pemandu silinder.
Selanjutnya, kita perlu memasang silinder ke blok dasar silinder. Namun sebelum kita melakukannya, kita harus memasang saklar batas mikro pada tempatnya.
Pertama, kita perlu menyolder kabelnya, pada sambungan NC. Panjang kabel harus sekitar 15cm. Kabel dimasukkan melalui lubang di bagian atas silinder, lalu kita dapat memasang sakelar batas mikro ke silinder dengan bantuan dua baut M2 dengan panjang 8mm.
Anda memerlukan sakelar batas mikro khusus ini agar bantalan pemandu dapat memicunya pada waktu yang tepat, tanpa membentur benda lain.
Jika Anda tidak bisa menemukan model limit switch yang tepat, tentunya Anda bisa memodifikasi lubang dan mekanismenya.
Untuk memasang silinder ke blok dasar kita perlu memasang beberapa sisipan berulir di sini. Kemudian kita kencangkan pada tempatnya menggunakan dua buah baut M4 dengan panjang 25mm. Saat ini kita harus memasukkan dua baut teratas saja.
Dua bagian bawah akan digunakan nanti saat memasang gearbox dan penutup PCB karena lubang yang sama digunakan untuk mengencangkan penutup.
Selanjutnya, kita dapat memasang batang ke dalam sekrup utama. Bantalan pemandu harus berada di antara rel pemandu pada silinder.
Dengan memutar roda gigi di sisi belakang, batang akan bergerak mundur hingga mencapai saklar batas mikro.
Kemudian, kita bisa memasang tutup silinder pada tempatnya. Tutup silinder akan menampung empat bantalan kecil dengan diameter luar 9mm. Poros untuk bantalan ini dapat dicetak 3D.
Kita harus berhati-hati saat memasangkannya pada tempatnya, karena bagian porosnya cukup kecil dan mudah patah. Ini terjadi beberapa kali pada saya, jadi pastikan ukurannya pas. Bantalan ini akan menopang dan memandu batang untuk pengoperasian yang lebih lancar.
Tutup silinder terpasang dengan empat baut M4.
Memasang motor DC
Ok selanjutnya kita masukkan motor DC pada tempatnya. Kami mengamankan motor DC dengan enam baut M3. Kemudian kita bisa memasang roda gigi ke poros motor.
Untuk mengencangkan roda gigi pada tempatnya, kami menggunakan dua sisipan berulir dan sekrup grub.
Setelah roda gigi dipasangkan dengan benar, kita dapat melanjutkan dengan memasang roda gigi dan penutup PCB di sisi belakang aktuator linier. Untuk itu, pertama-tama kita perlu memasang beberapa sisipan berulir lagi ke dalam blok dasar silinder.
Kemudian kita bisa menghubungkan kabel ke motor DC. Dalam kasus saya, saya langsung menyoldernya ke motor DC.
Panjang kabel harus sekitar 20cm. Ada lubang di blok dasar silinder tempat kita harus melewatkan kabel motor DC dan sakelar batas.
Lalu kita juga harus memasukkannya ke dalam dua penahan di penutup, yang akan memastikannya menjauh dari roda gigi.
Pada titik ini, kita dapat mengamankan penutup ke blok dasar. Untuk itu, pertama-tama kita perlu memasukkan kedua baut M4 di sisi bawah, tetapi jangan sampai masuk seluruhnya.
Kita harus menyisakan sekitar 2mm atau 3mm, sehingga kita dapat menempatkan dudukan penutup di antara keduanya, lalu kencangkan baut tersebut bersama dengan penutupnya.
Keseluruhan pengoperasian ini agak berantakan, namun harus seperti itu karena saya ingin sampulnya sekecil mungkin dan memiliki cetakan tunggal, dan penahan PCB menghalangi jalan baut.
Memasang PCB pengontrol servo khusus
Bagaimanapun, setelah kita selesai dengan penutupnya, kita dapat memasang papan pengontrol motor servo khusus di tempatnya. Seperti yang saya katakan, ini adalah pengontrol yang sama dari video saya sebelumnya di mana saya menunjukkan kepada Anda bagaimana Anda dapat mengubah motor DC apa pun menjadi motor servo.
Komponen utama di sini adalah encoder posisi putar magnetik AS5600, yang melacak posisi sudut magnet yang dipasang pada poros keluaran. Dalam hal ini kita akan memasang magnet ke roda gigi keluaran pada sekrup utama. Magnet akan sejajar sempurna dengan sensor AS5600 saat PCB dipasang.
Untuk mengencangkan PCB, pertama-tama kita perlu memasukkan mur M2 ke dalam slot dudukannya, lalu kencangkan PCB dengan empat baut M2.
Yang perlu dilakukan sekarang adalah menyambungkan kabel pada tempatnya. Kabel motor DC menuju ke blok terminal motor, dan polaritasnya juga harus diperiksa agar sesuai dengan program pengontrol.
Sebenarnya, sebelum menghubungkan motor ke PCB, kita dapat memberikan tegangan tertentu untuk memeriksa apakah mekanisme sekrup utama berfungsi dengan baik.
Sedangkan untuk kabel limit switch, karena saya tidak memiliki pin khusus untuk tujuan ini, saya menyolder kabel ground ke ground pad pada kapasitor elektrolitik, dan kabel sambungan NC ke pin SCK, yaitu pin digital nomor 13 pada mikrokontroler ATMEGA328.
Blok terminal daya berada tepat di sebelah sisi penutup, jadi ada lubang untuk menyambungkan konektor daya 5,5 mm.
Saya juga menambahkan heat sink pada driver motor DC. Terakhir, kita dapat memasang penutup snap-fit di sisi belakang dan selesai, proyek ini selesai.
Sekarang kita dapat menghubungkan segala jenis potensiometer atau penerima RC ke pin masukan yang sesuai, dan kita dapat mengontrol posisi aktuator linier dengannya.
Seperti yang sudah saya sebutkan, di video saya sebelumnya saya sudah menjelaskan secara detail cara kerja controller ini, skema rangkaiannya dan cara saya membuat PCBnya.
Jadi, Anda harus memeriksa tutorial itu jika Anda ingin membuat papan pengontrol ini.
Skema Sirkuit
Sangat cepat, komponen utamanya adalah sensor magnetik AS5600, yang melacak posisi keluaran aktuator. Data sensor masuk ke otak papan pengontrol servo ini, mikrokontroler Atmega328, yang melakukan perhitungan, dan memberi tahu driver motor DC DRV8871 cara menggerakkan motor DC.
Driver motor DC DRV8871 dapat menangani arus puncak hingga 3,6A. Untuk memberi daya pada board, kita dapat menggunakan 12V yang kemudian diturunkan menjadi 5V dengan pengatur tegangan ASM1117 untuk Atmega328 dan komponen 5V lainnya. Ada saklar DIP dua saluran yang melaluinya kita memilih mode input aktuator, baik analog atau digital, atau melalui komunikasi port serial.
Salah satu potensiometer pemangkas digunakan untuk mengatur sensitivitas aktuator, dan tombol tekan SDM digunakan untuk mengatur posisi awal dan akhir.
Saya memesan PCB dari PCBWay. Di sini kita cukup mengunggah file Gerber, memilih properti PCB kita, dan memesannya dengan harga yang wajar.
Saya mendesain PCB memiliki 4 lapisan, yang tengah untuk GND, yang sedikit menaikkan harga. Saya tidak mengubah properti default apa pun kecuali warna PCB yang saya pilih menjadi putih, dan saya centang bahwa saya menerima perubahan untuk Surface finish menjadi Immersion gold jika berlaku tanpa biaya tambahan.
Anda dapat menemukan dan mendownload Gerber dari komunitas berbagi proyek PCBWay, yang melaluinya Anda juga dapat memesan PCB secara langsung.
Bagaimanapun, Anda juga dapat membuat proyek aktuator linier ini bahkan tanpa pengontrol servo yang dibuat khusus ini, tentunya.
Anda dapat menggunakan sensor AS5600 pada breakout board yang dikombinasikan dengan board Arduino untuk mengendalikan motor DC.
Kode
Sekarang mari kita lihat kode Aktuator Servo Linier ini:
/*
Linear Servo Actuator - Arduino Code
by Dejan, www.HowToMechatronics.com
Libraries:
AS5600 encoder: https://github.com/RobTillaart/AS5600
PID conroller: https://github.com/br3ttb/Arduino-PID-Library/blob/master/PID_v1.h
*/
#include "AS5600.h"
#include "Wire.h"
#include <PID_v1.h>
AS5600 as5600; // use default Wire
double Pk1 = 0.65; //speed it gets there
double Ik1 = 0;
double Dk1 = 0.1;
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
PID myPID(&Input, &Output, &Setpoint, Pk1, Ik1, Dk1, DIRECT);
#define motor_IN1 5
#define motor_IN2 6
#define ch1 2
#define setButton 7
#define inputSwitch 3
#define modeSwitch 4
#define limitSwitch 13
int ch1Value;
long encoderValue, desiredValue, pwmValue;
String serialInput = ""; // string to hold input
int serialIntInput;
double totalDistance = 0;
long startPosition = 358;
long endPosition = 6750;
long rangeAdjustment = 0;
float sensitivityAdjustment = 0;
float angle = 0;
float angleValue = 0;
float rodPosition;
float positionsArray[100];
int positionsCounter = 0;
long quadrantNumber = 2;
long previousQuadrantNumber = 3;
long numberOfTurns = 0;
float totalAngle = 0;
char incomingByte = 0;
int intInput = 0;
void setup() {
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("AS5600_LIB_VERSION: ");
Serial.println(AS5600_LIB_VERSION);
Wire.begin();
pinMode(motor_IN1, OUTPUT);
pinMode(motor_IN2, OUTPUT);
// Activate the Arduino internal pull-up resistors
pinMode(setButton, INPUT_PULLUP);
pinMode(inputSwitch, INPUT_PULLUP);
pinMode(modeSwitch, INPUT_PULLUP);
pinMode(limitSwitch, INPUT_PULLUP);
// PID Setup
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(-255, 255);
myPID.SetSampleTime(20);
// --- HOMING ----
// Move backward until you ...
while (digitalRead(limitSwitch) != 1) {
digitalWrite(motor_IN1, LOW);
analogWrite(motor_IN2, 70);
encoderValue = as5600.readAngle();
}
while (digitalRead(limitSwitch) != 0) {
analogWrite(motor_IN1, 50);
digitalWrite(motor_IN2, LOW);
}
digitalWrite(motor_IN1, LOW);
digitalWrite(motor_IN2, LOW);
startPosition = as5600.readAngle() * 0.087890625;
endPosition = 6000;
Setpoint = startPosition;
// --- HOMING End ---
}
void loop() {
// Read encoder value - current position
rodPosition = as5600.readAngle() / 0.001953125; // in millimters - The lead screw is 8mm per rotation, and the encoder RAW value is 4096 per roration, so 8/4096 to get the value in milimiters
// Serial communication mode - Read data from the serial monitor
if (digitalRead(modeSwitch) == 0) {
while (Serial.available() > 0) {
serialInput = Serial.readString();
serialInput.trim();
// If "save" string is sent through the serial monitor, save the current rodPosition into the array
if (serialInput == "save") {
positionsArray[positionsCounter] = totalDistance;
delay(1000);
positionsCounter++;
}
// Clear the saved positions
if (serialInput == "clear") {
// Clear the array data to 0
memset(positionsArray, 0, sizeof(positionsArray));
positionsCounter = 0;
}
// Convert the String to Integer and use it as a Setpoint for the PID control
serialIntInput = serialInput.toInt();
if (serialIntInput != 0) {
if (serialIntInput < 0) {
serialIntInput = 0;
}
if (serialIntInput > 150) {
serialIntInput = 150;
}
Setpoint = serialIntInput * 45; // convert mm into degrees (1mm linear movement equals 45 degrees rotational movement)
}
}
// Run stored positions
if (serialInput == "run") {
while (serialInput != "stop") {
for (int i = 0; i <= positionsCounter - 1; i++) {
if (serialInput == "stop") {
break;
}
while (positionsArray[i] > totalDistance + 25 || positionsArray[i] < totalDistance - 25 || pwmValue != 0) {
// Desired position / setpoint for the PID contorller
Setpoint = positionsArray[i];
// Read encoder - use that value as an Input for the PID control
readEncoder();
// Run motor - PID controller inside
runMotor();
}
delay(2000); // Delay between steps
// Check the serial monitor for a stop command
while (Serial.available() > 0) {
serialInput = Serial.readString();
serialInput.trim();
}
}
}
}
}
// Potentiometer and RC Receiver control mode
else if (digitalRead(modeSwitch) == 1) {
if (digitalRead(inputSwitch) == 0) { // Analog input - Potentiometer
// Get value from potentiometer
desiredValue = analogRead(A0);
if (desiredValue < 15) {
desiredValue = 15;
}
if (desiredValue > 1008) {
desiredValue = 1008;
}
Setpoint = map(desiredValue, 15, 1008, startPosition, endPosition);
} else if (digitalRead(inputSwitch) == 1) { // Digital input - RC transmitter
desiredValue = pulseIn(ch1, HIGH, 30000); // Read RC receiver as input
if (desiredValue < 1000 || desiredValue > 2000) {
desiredValue = 1000;
}
Setpoint = map(desiredValue, 1000, 2000, startPosition, endPosition);
}
}
// Confine the minimum and maximum values of the setpoint
if (Setpoint > endPosition) {
Setpoint = endPosition;
}
if (Setpoint < startPosition) {
Setpoint = startPosition;
}
// Adjusting sensitivity
//Pk1 = analogRead(A2) * 0.002; // Adjust the PID gain term
//myPID.SetTunings(Pk1, Ik1, Dk1);
// Read encoder - use that value as an input for the PID control
readEncoder();
// Run motor
runMotor();
// Set start and end positions by pressing the "set" button
if (digitalRead(setButton) == LOW) {
delay(3000);
if (digitalRead(setButton) == LOW) {
endPosition = totalDistance;
while (digitalRead(setButton) != HIGH)
;
} else {
startPosition = totalDistance;
}
}
}
void readEncoder() {
// Convert encoder RAW values into angle values for keeping track of the angular position of the shaft
encoderValue = as5600.readAngle() * 0.087890625;
// Quadrant 1
if (encoderValue >= 0 && encoderValue <= 90) {
quadrantNumber = 1;
}
// Quadrant 2
if (encoderValue >= 90 && encoderValue <= 180) {
quadrantNumber = 2;
}
// Quadrant 3
if (encoderValue >= 180 && encoderValue <= 270) {
quadrantNumber = 3;
}
// Quadrant 4
if (encoderValue >= 270 && encoderValue <= 360) {
quadrantNumber = 4;
}
if (quadrantNumber != previousQuadrantNumber) {
// Transition from 4th to 1st quadrant
if (quadrantNumber == 1 && previousQuadrantNumber == 4) {
numberOfTurns++;
}
// Transition from 1st to 4th quadrant
if (quadrantNumber == 4 && previousQuadrantNumber == 1) {
numberOfTurns--;
}
previousQuadrantNumber = quadrantNumber;
}
if (totalDistance >= 0) {
totalDistance = (numberOfTurns * 360) + encoderValue;
} else {
totalDistance = (numberOfTurns * 360) + encoderValue;
}
// Establish Input value for PID
Input = totalDistance; // current value of the position
}
void runMotor() {
// Run PID process to get Output value
myPID.Compute();
// Move right
if (Output > 1) {
pwmValue = Output;
if (pwmValue < 50 && pwmValue > 15) {
pwmValue = pwmValue + 40;
}
if (pwmValue <= 15) {
pwmValue = 0;
}
analogWrite(motor_IN1, pwmValue);
digitalWrite(motor_IN2, LOW);
}
// Move left
else if (Output < 1) {
pwmValue = abs(Output);
if (pwmValue < 50 && pwmValue > 15) {
pwmValue = pwmValue + 40;
}
if (pwmValue <= 15) {
pwmValue = 0;
}
digitalWrite(motor_IN1, LOW);
analogWrite(motor_IN2, pwmValue);
}
// Do not move
else if (Output > -1 && Output < 1) {
pwmValue = 0;
digitalWrite(motor_IN1, LOW);
digitalWrite(motor_IN2, LOW);
}
}
Code language: PHP (php)
Deskripsi Kode
Jadi, kita memulai loop dengan membaca nilai encoder atau posisi aktuator saat ini dan mengubahnya menjadi milimeter.
// Read encoder value - current position
rodPosition = as5600.readAngle() / 0.001953125; // in millimters - The lead screw is 8mm per rotation, and the encoder RAW value is 4096 per roration, so 8/4096 to get the value in milimiters
Code language: PHP (php)
Kemudian jika kita berada pada “mode komunikasi Serial” kita membaca data masuk yang kita masukkan pada Serial monitor. Jika inputnya “simpan” kami menyimpan aktuator posisi saat ini, atau jika “bersih” kami menghapus semua posisi yang sudah disimpan.
// Serial communication mode - Read data from the serial monitor
if (digitalRead(modeSwitch) == 0) {
while (Serial.available() > 0) {
serialInput = Serial.readString();
serialInput.trim();
// If "save" string is sent through the serial monitor, save the current rodPosition into the array
if (serialInput == "save") {
positionsArray[positionsCounter] = totalDistance;
delay(1000);
positionsCounter++;
}
// Clear the saved positions
if (serialInput == "clear") {
// Clear the array data to 0
memset(positionsArray, 0, sizeof(positionsArray));
positionsCounter = 0;
}Code language: JavaScript (javascript)
Jika inputnya berupa bilangan bulat atau angka, dari 0 hingga 150, kami menggunakan nilai tersebut sebagai setpoint.
// Convert the String to Integer and use it as a Setpoint for the PID control
serialIntInput = serialInput.toInt();
if (serialIntInput != 0) {
if (serialIntInput < 0) {
serialIntInput = 0;
}
if (serialIntInput > 150) {
serialIntInput = 150;
}
Setpoint = serialIntInput * 45; // convert mm into degrees (1mm linear movement equals 45 degrees rotational movement)
}
}Code language: JavaScript (javascript)
Kita memasukkan nilai dalam milimeter, tetapi untuk melacak poros yang berputar, kita menggunakan derajat, jadi oleh karena itu kita mengubah nilai milimeter menjadi nilai derajat dengan mengalikannya dengan 45. Itu sebabnya karena untuk gerakan linier 1mm, sekrup utama harus berputar 45 derajat. Jika Anda memiliki nada berbeda pada sekrup utama, angka ini harus berbeda.
Jika kita mengetik “run”, dengan bantuan beberapa loop while dan for, program akan berjalan melalui posisi yang disimpan berulang kali.
// Run stored positions
if (serialInput == "run") {
while (serialInput != "stop") {
for (int i = 0; i <= positionsCounter - 1; i++) {
if (serialInput == "stop") {
break;
}
while (positionsArray[i] > totalDistance + 25 || positionsArray[i] < totalDistance - 25 || pwmValue != 0) {
// Desired position / setpoint for the PID contorller
Setpoint = positionsArray[i];
// Read encoder - use that value as an Input for the PID control
readEncoder();
// Run motor - PID controller inside
runMotor();
}
delay(2000); // Delay between steps
// Check the serial monitor for a stop command
while (Serial.available() > 0) {
serialInput = Serial.readString();
serialInput.trim();
}
}
}
}Code language: JavaScript (javascript)
Di sisi lain, jika kita berada dalam mode kontrol Potensiometer dan penerima RC, kita memeriksa apakah kita memiliki input analog atau digital.
// Potentiometer and RC Receiver control mode
else if (digitalRead(modeSwitch) == 1) {
if (digitalRead(inputSwitch) == 0) { // Analog input - Potentiometer
// Get value from potentiometer
desiredValue = analogRead(A0);
if (desiredValue < 15) {
desiredValue = 15;
}
if (desiredValue > 1008) {
desiredValue = 1008;
}
Setpoint = map(desiredValue, 15, 1008, startPosition, endPosition);
} else if (digitalRead(inputSwitch) == 1) { // Digital input - RC transmitter
desiredValue = pulseIn(ch1, HIGH, 30000); // Read RC receiver as input
if (desiredValue < 1000 || desiredValue > 2000) {
desiredValue = 1000;
}
Setpoint = map(desiredValue, 1000, 2000, startPosition, endPosition);
}
}Code language: JavaScript (javascript)
Jika analog, kita membaca input analog dari potensiometer dan menggunakan nilai tersebut sebagai Setpoint, atau posisi yang diinginkan untuk dituju oleh aktuator. Demikian pula, jika inputnya digital, kita membaca data yang masuk dari penerima RC dan menggunakan nilai tersebut sebagai setpoint.
Kemudian kita memanggil fungsi khusus readEncoder() dan runMotor() untuk membaca posisi aktuator saat ini dan menjalankan kontrol PID. Dengan fungsi readEncoder() kita membaca nilai sensor saat ini dalam nilai sudut, dan dengan pernyataan if ini kita melacak di kuadran mana posisi poros saat ini.
void readEncoder() {
// Convert encoder RAW values into angle values for keeping track of the angular position of the shaft
encoderValue = as5600.readAngle() * 0.087890625;
// Quadrant 1
if (encoderValue >= 0 && encoderValue <= 90) {
quadrantNumber = 1;
}
// Quadrant 2
if (encoderValue >= 90 && encoderValue <= 180) {
quadrantNumber = 2;
}
// Quadrant 3
if (encoderValue >= 180 && encoderValue <= 270) {
quadrantNumber = 3;
}
// Quadrant 4
if (encoderValue >= 270 && encoderValue <= 360) {
quadrantNumber = 4;
}
if (quadrantNumber != previousQuadrantNumber) {
// Transition from 4th to 1st quadrant
if (quadrantNumber == 1 && previousQuadrantNumber == 4) {
numberOfTurns++;
}
// Transition from 1st to 4th quadrant
if (quadrantNumber == 4 && previousQuadrantNumber == 1) {
numberOfTurns--;
}
previousQuadrantNumber = quadrantNumber;
}
if (totalDistance >= 0) {
totalDistance = (numberOfTurns * 360) + encoderValue;
} else {
totalDistance = (numberOfTurns * 360) + encoderValue;
}
// Establish Input value for PID
Input = totalDistance; // current value of the position
}Code language: HTML, XML (xml)
Dengan informasi ini, kita dapat mengetahui bagaimana poros berputar dan kapan akan berputar penuh. Sudut total adalah nilai Input untuk pengontrol PID.
Dengan menggunakan masukan analog dari potensiometer pemangkas kita dapat mengatur penguatan proporsional pengontrol PID, dan terakhir kita menjalankan proses PID untuk mendapatkan nilai keluaran.
// Adjusting sensitivity
//Pk1 = analogRead(A2) * 0.002; // Adjust the PID gain term
//myPID.SetTunings(Pk1, Ik1, Dk1);Code language: JSON / JSON with Comments (json)
void runMotor() {
// Run PID process to get Output value
myPID.Compute();
// Move right
if (Output > 1) {
pwmValue = Output;
if (pwmValue < 50 && pwmValue > 15) {
pwmValue = pwmValue + 40;
}
if (pwmValue <= 15) {
pwmValue = 0;
}
analogWrite(motor_IN1, pwmValue);
digitalWrite(motor_IN2, LOW);
}
// Move left
else if (Output < 1) {
pwmValue = abs(Output);
if (pwmValue < 50 && pwmValue > 15) {
pwmValue = pwmValue + 40;
}
if (pwmValue <= 15) {
pwmValue = 0;
}
digitalWrite(motor_IN1, LOW);
analogWrite(motor_IN2, pwmValue);
}
// Do not move
else if (Output > -1 && Output < 1) {
pwmValue = 0;
digitalWrite(motor_IN1, LOW);
digitalWrite(motor_IN2, LOW);
}
}Code language: JavaScript (javascript)
Nilai output tersebut kita gunakan untuk menggerakkan motor DC dengan sinyal PWM, kiri atau kanan, atau dalam posisi diam tergantung pada nilai output dari pengontrol PID, atau tergantung pada kesalahan antara posisi yang diinginkan dan posisi sebenarnya yang dibaca encoder.
Ketiga istilah pengontrol PID, proporsional, integral, dan turunan didefinisikan di bagian atas, dan dengan menyesuaikannya kita bisa mendapatkan berbagai respons keluaran.
double Pk1 = 0.65; //speed it gets there
double Ik1 = 0;
double Dk1 = 0.1;Code language: JavaScript (javascript)
Kualitas, seberapa baik aktuator akan bekerja atau merespons masukan kami secara langsung bergantung pada nilai-nilai ini.
Pengujian
Di sini saya menguji akurasi aktuator. Itu akan kembali ke tempatnya dengan baik. Kemudian seorang mulai menggerakkan batang itu satu milimeter pada satu waktu. Gerakan pertama seperti 0,8 mm, bukan 1 mm, tetapi 4 gerakan berikutnya cukup dekat hingga 1 mm. Kemudian gerakan 4mm berkurang sekitar 0,15mm.
Kita harus memperhatikan bahwa batang memiliki serangan balik sekitar 0,25 mm. Serangan balik ini terjadi antara sekrup utama dan mur sekrup utama. Selain itu, kami mungkin memiliki beberapa reaksi negatif pada roda gigi cetak 3D serta roda gigi motor DC itu sendiri.
Jika kita menerapkan gaya pada batang dan menguji keakuratannya sekarang, tentu saja, kita akan mendapatkan kesalahan yang lebih besar, namun hal ini dapat diperbaiki dengan mengubah pengontrol PID.
Namun demikian, itu saja untuk tutorial ini. Saya harap Anda menikmatinya dan mempelajari sesuatu yang baru.