Robot Pemecah Labirin Berbasis AI Menggunakan Arduino dan Bluetooth
Komponen dan Perlengkapan
- Arduino Nano R3: 1 buah
- Modul Bluetooth HC-06: 1 buah
- TCRT5000 4CH Infrared Line Track Follower Sensor Module: 1 buah
- SparkFun RedBot Sensor - Line Follower: 1 buah
- ZX03 (based on TCRT5000) Reflective Infrared Sensors (Analog output): 2 buah
- Perangkat Android: 1 buah
- RobotGeek Continuous Rotation Servo: 2 buah
- 4xAA battery holder: 2 buah
Aplikasi dan layanan online:
- Arduino IDE
- MIT App Inventor 2
Tentang Proyek Ini
Pendahuluan
Tutorial ini dikembangkan berdasarkan proyek terakhir saya: Line Follower Robot - PID Control - Android Setup. Setelah Anda memiliki robot dengan kemampuan mengikuti garis, langkah alami berikutnya adalah memberinya beberapa tingkat kecerdasan. Jadi, robot kesayangan kami "Rex, the Robot" sekarang akan mencoba menemukan cara untuk keluar dari "labirin" dengan cara yang tercepat dan paling efisien (sepasang, dia benci Minotaurus).
Untuk memulai, apa perbedaan antara Maze dan Labyrinth? Menurut https://www.labyrinthos.net, di dunia berbahasa Inggris sering dianggap bahwa untuk memenuhi syarat sebagai labirin, desain harus memiliki pilihan di dalam jalan. Jelas, ini akan mencakup banyak instalasi modern di taman hiburan dan atraksi wisata, termasuk labirin 2D kami di sini. Konsensi populer juga menunjukkan bahwa labirin memiliki satu jalan yang mengarah tak terhindarkan dari pintu masuk ke tujuan, meskipun sering kali melalui rute yang paling kompleks dan berbelok-belok.
Sebagian besar labirin, seberapa kompleks pun desainnya tampak, pada dasarnya dibentuk dari satu dinding yang kontinu dengan banyak persimpangan dan cabang. Jika dinding yang mengelilingi tujuan labirin terhubung dengan perimeter labirin di pintu masuk, labirin selalu dapat diselesaikan dengan memegang satu tangan dalam kontak dengan dinding, seberapa banyak lintasan yang mungkin terlibat. Labirin 'sederhana' ini dengan benar dikenal sebagai 'Simply-connected' atau 'perfect maze' atau dengan kata lain, yang tidak mengandung loop.
Kembali ke proyek kami, ini akan dibagi menjadi dua bagian (atau 'passes'):
- (Pass Pertama): Robot menemukan jalan keluar dari '
non-known perfect maze '. Tidak masalah di mana Anda menaruhnya di dalam labirin, itu akan menemukan 'solusi'.
- (Pass Kedua): Setelah robot menemukan solusi labirin yang mungkin, itu harus mengoptimalkan solusinya menemukan '
jalur terpendek dari awal hingga akhir'.
Video di bawah ini akan menunjukkan contoh Rex menemukan jalan keluar. Pada kali pertama robot menjelajahi labirin, tentu saja itu akan membuang banyak waktu 'memikirkan' apa yang harus dilakukan di setiap persimpangan. Menguji kemungkinan yang banyak, itu akan mengambil beberapa jalan salah dan jalan buntu, yang memaksa dia untuk menjalani jalur yang lebih panjang dan melakukan 'U-Turns' yang tidak perlu. Selama '1st Pass' ini, robot akan mengumpulkan pengalaman, 'mencatat catatan' tentang persimpangan yang berbeda dan menghapus cabang yang buruk. Pada '2nd Pass'nya, robot lurus dan cepat ke akhir tanpa kesalahan atau ragu-ragu. Sepanjang tutorial ini, kita akan menjelajahi secara rinci cara melakukannya:
Langkah 1: Daftar Bahan
Daftar bahan pada dasarnya sama dengan yang digunakan dengan Line Follower Robot, kecuali bahwa saya menyertakan 2 sensor tambahan untuk akurasi yang lebih baik dalam mendeteksi persimpangan KIRI dan KANAN:
Robot akhir masih sangat murah (sekitar $ 85,00):
Tubuh (Anda dapat menyesuaikannya dengan kebutuhan atau bahan yang tersedia):
- 2 X Persegi kayu (80X80mm)
- 3 X Klip pembinder
- 2 X Roda kayu (diameter: 50mm)
- 1 X Ball caster
- 9 X Rangka karet
- 3M Command frame strip
- Sekrup plastik untuk penyesuaian sensor
- BreadBoard dan kabel
- 2 X set 4XNi-Metal Hydride Baterai (5V setiap set)
- 2 X SM-S4303R Continuous Rotation 360 Degree Plastic Servo
- Arduino Nano
- HC-06 Bluetooth module
- 5 X Sensor garis (TCRT5000 4CH Infrared Line Track Follower Sensor Module + 1 sensor jejak independen)
- 2 X ZX03 (based on TCRT5000) Reflective Infrared Sensors (Analog output)
- 1 LED
- 1 tombol
Catatan: Saya menggunakan item 7 di atas dengan output analog, karena saya tidak memiliki sensor dengan output digital seperti pada item 6. Idealnya memiliki semua sensor yang sama, jika memungkinkan. Saya juga menguji proyek hanya dengan 5 sensor asli. Itu akan bekerja, tetapi memerlukan penyesuaian yang lebih sensitif dalam menemukan persimpangan.
Langkah 2: Perubahan pada Tubuh
Hapus set asli 5 Line Follow Sensors dan pasang sensor refleksi 'Far LEFT' dan 'Far RIGHT' baru di setiap ujung baris plastik pendukung. Disarankan untuk memiliki 7 sensor yang sejajar sebaik mungkin.
Langkah 3: Memasang dan Menguji Sensor Baru
Array sensor baru yang sekarang 7 sensor, dipasang dengan cara sehingga 5 asli digunakan secara eksklusif untuk kontrol PID (dan deteksi 'garis penuh', dijelaskan nanti) dan 2 yang baru, kiri dan kanan, digunakan secara eksklusif untuk deteksi persimpangan KIRI dan KANAN.
Sebagai tinjauan cepat, mari kita ingat cara kerja 5 sensor 'digital' asli:
Jika satu sensor berpusat dengan garis hitam, hanya sensor spesifik itu akan menghasilkan HIGH. Di sisi lain, spasi di antara sensor harus dihitung untuk memungkinkan 2 sensor menutupi lebar penuh garis hitam secara bersamaan, juga menghasilkan sinyal HIGH pada kedua sensor.
Cara kerja 2 sensor 'analog' baru:
Jika salah satu sensor berpusat dengan garis hitam, outputnya akan menjadi nilai analog, biasanya menghasilkan output di Arduino ADC di bawah '100' (ingat bahwa ADC menghasilkan output dari 0 hingga 1023). Dengan permukaan yang lebih terang, nilai output akan lebih tinggi (Saya menguji 500 hingga 600 di atas kertas putih, misalnya). Nilai ini harus diuji dalam situasi cahaya dan bahan permukaan yang berbeda untuk menentukan konstanta THRESHOLD yang benar untuk digunakan dalam kasus Anda (lihat gambar di sini).
Melihat kode Arduino, masing-masing sensor akan didefinisikan dengan nama spesifik (anggaplah bahwa sensor Line Follow asli yang lebih ke Kiri harus ditugaskan dengan label '0 '):
const int lineFollowSensor0 = 12; //Using Digital input const int lineFollowSensor1 = 18; //Using Analog Pin A4 as Digital input const int lineFollowSensor2 = 17; //Using Analog Pin A3 as Digital input const int lineFollowSensor3 = 16; //Using Analog Pin A2 as Digital input const int lineFollowSensor4 = 19; //Using Analog Pin A5 as Digital input const int farRightSensorPin = 0; //Analog Pin A0 const int farLeftSensorPin = 1; //Analog Pin A1
Untuk diingat, output array 5 sensor asli saat mengikuti garis adalah:
1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 0 1 0 0 0 1 1 0 0 0 1 0 0 0 1 1 0 0 0 1 0 0 0 1 1 0 0 0 1 0 0 0 0
Ditambahkannya 2 sensor baru, output yang mungkin adalah:
- Sensor Far LEFT: Output Analog lebih tinggi atau lebih rendah dari THRESHOLD
- Sensor Far RIGHT: Output Analog lebih tinggi atau lebih rendah dari THRESHOLD
Untuk menyimpan nilai setiap sensor, variabel array dibuat untuk 5 sensor digital asli:
int LFSensor[5]={0, 0, 0, 0, 0};
Dan dua variabel integer untuk 2 sensor analog baru:
int farRightSensor = 0; int farLeftSensor = 0;
Setiap posisi array dan variabel akan terus diperbarui dengan output dari masing-masing sensor:
LFSensor[0] = digitalRead(lineFollowSensor0); LFSensor[1] = digitalRead(lineFollowSensor1); LFSensor[2] = digitalRead(lineFollowSensor2); LFSensor[3] = digitalRead(lineFollowSensor3); LFSensor[4] = digitalRead(lineFollowSensor4); farRightSensor = analogRead(farRightSensorPin); farLeftSensor = analogRead(farLeftSensorPin);
Memiliki 5 sensor, seperti yang terlihat dalam proyek Follower Line Robot, memungkinkan pembuatan 'variabel error' yang akan membantu mengontrol posisi robot di atas garis. Juga, variabel yang disebut 'mode' akan digunakan untuk definisi apakah robot mengikuti garis, di atas garis kontinu, persimpangan atau tidak ada garis sama sekali.
Variabel 'mode' ini juga akan digunakan dengan sensor 'Far LEFT/RIGHT'. Untuk representasi, anggaplah sensor kiri dan kanan jauh memiliki 3 kemungkinan status:
- H (lebih tinggi dari THRESHOLD),
- L (lebih rendah dari THRESHOLD) dan
- X (tidak relevan).
Untuk output digital, akan 0, 1 biasa dan kita juga akan memperkenalkan X:
- H 0 X X X X L ==> mode = RIGHT_TURN; error = 0; (lihat contoh di gambar di atas)
- L X X X X 0 H ==> mode = LEFT_TURN; error = 0;
- X 0 0 0 0 0 X ==> mode = NO_LINE; error = 0;
- H 0 0 0 0 1 H ==> mode = FOLLOWING_LINE; error = 4;
- H 0 0 0 1 1 H ==> mode = FOLLOWING_LINE; error = 3;
- H 0 0 0 1 0 H ==> mode = FOLLOWING_LINE; error = 2;
- H 0 0 1 1 0 H ==> mode = FOLLOWING_LINE; error = 1;
- H 0 0 1 0 0 H ==> mode = FOLLOWING_LINE; error = 0;
- H 0 1 1 0 0 H ==> mode = FOLLOWING_LINE; error = -1;
- H 0 1 0 0 0 H ==> mode = FOLLOWING_LINE; error = -2
- H 1 1 0 0 0 H ==> mode = FOLLOWING_LINE; error = -3;
- H 1 0 0 0 0 H ==> mode = FOLLOWING_LINE; error = -4;
- X 1 1 1 1 1 X ==> mode = CONT_LINE; error = 0;
Jadi, mengimplementasikan logika di atas dalam fungsi:
void readLFSsensors()
akan mengembalikan variabel 'mode' dan 'error' yang akan digunakan pada logika program. Penting untuk menguji logika sensor sebelum melanjutkan proyek. Fungsi di bawah ini disertakan dalam kode dan dapat digunakan untuk keperluan pengujian:
void testSensorLogic(void) { Serial.print (farLeftSensor); Serial.print (" <== LEFT RIGH==> "); Serial.print (farRightSensor); Serial.print (" mode: "); Serial.print (mode); Serial.print (" error:"); Serial.println (error); }
Langkah 4: Memecahkan Labirin - Aturan Tangan Kiri
Seperti yang dibahas pada pendahuluan, sebagian besar labirin, seberapa kompleks pun desainnya tampak, pada dasarnya dibentuk dari satu dinding yang kontinu dengan banyak persimpangan dan cabang. Jika dinding yang mengelilingi tujuan labirin terhubung dengan perimeter labirin di pintu masuk, labirin selalu dapat diselesaikan dengan memegang satu tangan dalam kontak dengan dinding, seberapa banyak lintasan yang mungkin terlibat. Labirin 'sederhana' ini dengan benar dikenal sebagai 'Simply-connected .'
Mencari di Wikipedia, kita belajar bahwa:
Singkatnya, Left-Hand Rule dapat dijelaskan sebagai:
Di setiap persimpangan, dan sepanjang labirin, pegang tangan kiri Anda menyentuh dinding di kiri Anda.
- Letakkan tangan kiri Anda di dinding.
- Mulai berjalan ke depan
- Akhirnya, Anda akan mencapai akhir labirin. Anda mungkin tidak akan menempuh jalur terpendek dan paling langsung, tetapi Anda akan sampai di sana.
Jadi, kunci di sini adalah untuk mengidentifikasi persimpangan, menentukan arah yang akan diambil berdasarkan aturan di atas. Secara khusus dalam jenis labirin 2D kami, kita dapat menemukan 8 jenis persimpangan yang berbeda (lihat gambar pertama di atas):
Melihat gambar, kita dapat menyadari bahwa tindakan yang mungkin di persimpangan adalah:
1. Di 'Cross':
- Pergi ke Kiri, atau
- Pergi ke Kanan, atau
- Pergi Lurus
2. Di 'T':
- Pergi ke Kiri, atau
- Pergi ke Kanan
3. Di 'Right Only':
4. Di 'Left Only':
5. Di 'Straight or Left':
- Pergi ke Kiri, atau
- Pergi Lurus
6. Di 'Straight or Right':
- Pergi ke Kanan, atau
- Pergi Lurus
7. Di 'Dead End':
8. Di 'End of Maze':
Tetapi, menerapkan 'Left-Hand Rule', tindakan akan dikurangi menjadi satu opsi masing-masing:
- Di 'Cross': Pergi ke Kiri
- Di 'T': Pergi ke Kiri
- Di 'Right Only': Pergi ke Kanan
- Di 'Left Only': Pergi ke Kiri
- Di 'Straight or Left': Pergi ke Kiri
- Di 'Straight or Right': Pergi Lurus
- Di 'Dead End': Kembali ( 'U turn' )
- Di 'End of Maze': Berhenti
Kami hampir sampai! 'Tenang!'
Ketika robot mencapai 'Dead End' atau 'End of a Maze', mudah untuk mengidentifikasi mereka, karena tidak ada situasi ambigu (kami telah mengimplementasikan tindakan tersebut pada Line Follower Robot, ingat?). Masalahnya adalah ketika robot menemukan 'LINE' misalnya, karena garis bisa menjadi 'Cross' (1) atau 'T' (2). Juga ketika mencapai 'LEFT or RIGHT TURN', itu bisa menjadi belokan sederhana (opsional 3 atau 4) atau opsi untuk pergi lurus (5 atau 6). Untuk menemukan tepat jenis persimpangan mana tempat robot, langkah tambahan harus diambil: robot harus berjalan 'inci tambahan' dan melihat apa yang ada selanjutnya (lihat gambar kedua di atas, sebagai contoh).
Jadi, dalam hal alur, tindakan yang mungkin sekarang dapat digambarkan sebagai:
1. Di 'DEAD END':
2. Di 'LINE': Jalankan inci tambahan
- Jika ada garis: Ini adalah 'Cross' ==> Pergi ke KIRI
- Jika Tidak ada garis: itu adalah 'T' ==> Pergi ke KIRI
- Jika ada garis lain: itu adalah 'End of Maze' ==> BERHENTI
3. Di 'RIGHT TURN': Jalankan inci tambahan
- jika ada garis: Ini adalah Straight or Right ==> Pergi LURUS
- Jika tidak ada garis: itu adalah Right Only ==> Pergi ke KANAN
4. Di 'LEFT TURN': Jalankan inci tambahan
- jika ada garis: Ini adalah Straight or LEFT ==> Pergi ke KIRI
- Jika tidak ada garis: itu adalah LEFT Only ==> Pergi ke KIRI
Perhatikan bahwa sebenarnya, dalam kasus 'LEFT TURN', Anda dapat melewati tes, karena Anda akan mengambil KIRI bagaimanapun. Saya biarkan penjelasan lebih umum hanya untuk kejelasan. Dalam kode asli saya akan melewati tes ini. Gambar ke-3 di atas, menunjukkan labirin yang sangat sederhana di lantai laboratorium saya, digunakan untuk keperluan pengujian.
Langkah 5: Menerapkan Algoritma 'Left Hand on the Wall' di Kode Arduino
Setelah kita memiliki fungsi readLFSsensors() yang dimodifikasi untuk menyertakan 2 sensor tambahan, kita dapat menuliskan ulang fungsi Loop untuk menjalankan algoritma seperti yang dijelaskan pada Langkah terakhir:
void loop() { readLFSsensors(); switch (mode) { case NO_LINE: motorStop(); goAndTurn (LEFT, 180); break; case CONT_LINE: runExtraInch(); readLFSsensors(); if (mode == CONT_LINE) mazeEnd(); else goAndTurn (LEFT, 90); // or it is a "T" or "Cross"). In both cases, goes to LEFT break; case RIGHT_TURN: runExtraInch(); readLFSsensors(); if (mode == NO_LINE) goAndTurn (RIGHT, 90); break; case LEFT_TURN: goAndTurn (LEFT, 90); break; case FOLLOWING_LINE: followingLine(); break; } }
Beberapa fungsi baru muncul di sini:
- followingLine() sama dengan yang digunakan dengan Following Line Robot di mana, jika hanya mengikuti garis, harus
calculatePID(); dan mengontrol motor tergantung nilai PID: motorPIDcontrol(); - runExtraInch(): akan mendorong robot ke depan hanya sedikit. Seberapa jauh robot akan berjalan akan tergantung pada waktu yang Anda gunakan dalam fungsi delay, sebelum Anda memerintahkan motor untuk berhenti.
void runExtraInch(void) { motorPIDcontrol(); delay(extraInch); motorStop(); }
- goAndTurn (direction, angle): fungsi khusus ini penting karena Anda tidak dapat memutar robot segera setelah Anda menyadari jenis persimpangan tempat Anda. Ingatlah bahwa kita merancang Robot Diferensial yang saat berbelok, 'berputar di sekitar sumbu' dan jadi, untuk bergerak 90o dan terus mengikuti garis, pusat roda harus sejajar dengan pusat persimpangan. Setelah garis sensor berada di depan sumbu, Anda harus menjalankan robot ke depan untuk menyelaraskannya. Konstanta waktu
adjGoAndTurn harus disesuaikan tergantung pada jarak antara sumbu dan garis sensor ('d '), kecepatan dan ukuran roda (lihat gambar di atas untuk ilustrasi).
void goAndTurn(int direction, int degrees) { motorPIDcontrol(); delay(adjGoAndTurn); motorTurn(direction, degrees); }
Pada titik ini, robot sebenarnya 'memecahkan labirin'! Anda baru saja menyelesaikan 'Pass Pertama'. Tidak masalah di mana Anda memulai di dalam labirin, Anda akan selalu mencapai akhir.
Di bawah ini, uji fase ini dari proyek:
Langkah 6: Menyimpan Jalur
Mari kita pertimbangkan contoh seperti yang ditunjukkan dalam foto di atas. Di titik awal yang dipilih, robot akan menemukan 15 Persimpangan sebelum mencapai akhir Labirin:
- Kiri (L)
- Kembali (B)
- Kiri (L)
- Kiri (L)
- Kiri (L)
- Kembali (B)
- Lurus (S)
- Kembali (B)
- Kiri (L)
- Kiri (L)
- Kembali (B)
- Lurus (S)
- Kiri (L)
- Kiri (L)
- Akhir
Yang harus dilakukan di salah satu persimpangan tersebut, adalah menyimpan setiap tindakan yang dilakukan tepat dalam urutan yang sama yang terjadi. Untuk itu, mari kita buat variabel baru (array) yang akan menyimpan jalur yang telah ditempuh robot:
char path[100] = " ";
Kami juga harus membuat 2 variabel indeks yang akan digunakan bersama dengan array:
unsigned char pathLength = 0; // panjang jalur int pathIndex = 0; // digunakan untuk mencapai elemen array tertentu.
Jadi, jika kita menjalankan contoh yang ditunjukkan dalam gambar, kita akan akhirnya dengan:
path = [LBLLLBSBLLBSLL] dan pathLengh = 14
Langkah 7: Menyederhanakan (mengoptimalkan) Jalur
Mari kita kembali ke contoh kita. Melihat grup persimpangan pertama, kami menyadari bahwa cabang kiri pertama sebenarnya adalah 'Dead End' dan jadi, jika robot alih-alih 'Kiri-Kembali-Kiri' hanya melewati lurus di persimpangan pertama, banyak energi dan waktu akan terhemat! Dengan kata lain, urutan 'LBL' sebenarnya sama dengan 'S'. Itulah tepatnya bagaimana jalur penuh dapat dioptimalkan. Jika Anda menganalisis semua kemungkinan di mana 'U turn' digunakan, sekumpulan 3 persimpangan di mana 'U-Turn' ('B') muncul ('xBx') dapat dikurangi menjadi hanya satu.
Di atas hanyalah satu contoh, di bawah ini Anda dapat menemukan daftar lengkap kemungkinan (cobalah):
- LBR = B
- LBS = R
- RBL = B
- SBL = R
- SBS = B
- LBL = S
Mengambil jalur penuh dari contoh kami, kita dapat menguranginya:
path = [LBLLLBSBLLBSLL] ==> LBL = S path = [SLLBSBLLBSLL] ==> LBS = R path = [SLRBLLBSLL] ==> RBL = B path = [SLBLBSLL] ==> LBL = S path = [SSBSLL] ==> SBS = B path = [SBLL] ==> SBL = R path = [RL]
Luar biasa! Melihat contoh ini sangat jelas bahwa jika robot mengambil KANAN di persimpangan pertama dan setelah itu, KIRI, itu akan mencapai Akhir Labirin dengan jalur terpendek!
Path Pertama dari Kode Maze Solver akan dikonsolidasikan dalam fungsi mazeSolve(). Fungsi ini sebenarnya adalah fungsi loop() yang digunakan sebelumnya, tetapi menggabungkan semua langkah penyimpanan dan optimasi jalur tersebut. Ketika path pertama berakhir, array path[] akan memiliki jalur yang dioptimalkan. Variabel baru diperkenalkan:
unsigned int status = 0; // solving = 0; reach Maze End = 1
Di bawah fungsi Path Pertama:
void mazeSolve(void) { while (!status) { readLFSsensors(); switch (mode) { case NO_LINE: motorStop(); goAndTurn (LEFT, 180); recIntersection('B'); break; case CONT_LINE: runExtraInch(); readLFSsensors(); if (mode != CONT_LINE) {goAndTurn (LEFT, 90); recIntersection('L');} // or it is a "T" or "Cross"). In both cases, goes to LEFT else mazeEnd(); break; case RIGHT_TURN: runExtraInch(); readLFSsensors(); if (mode == NO_LINE) {goAndTurn (RIGHT, 90); recIntersection('R');} else recIntersection('S'); break; case LEFT_TURN: goAndTurn (LEFT, 90); recIntersection('L'); break; case FOLLOWING_LINE: followingLine(); break; } } }
Di sini fungsi baru diperkenalkan: recIntersection (direction). Fungsi ini akan digunakan untuk menyimpan persimpangan dan juga untuk memanggil fungsi lain simplifyPath(), yang akan mengurangi sekelompok 3 persimpangan yang melibatkan 'U-Turn' seperti yang kita lihat sebelumnya.
void recIntersection(char direction) { path[pathLength] = direction; // Store the intersection in the path variable. pathLength ++; simplifyPath(); // Simplify the learned path. }
KREDIT untuk fungsi simplifyPath() adalah Patrick McCabe untuk kode Path Solving (untuk detail, kunjungi https://patrickmccabemakes.com)! Strategi Penyederhanaan Jalur adalah setiap kali kita menemui urutan xBx, kita dapat menyederhanakannya dengan menghapus jalan buntu. Misalnya, LBL ==> S seperti yang kita lihat pada contoh.
void simplifyPath() { // only simplify the path if the second-to-last turn was a 'B' if(pathLength < 3 || path[pathLength-2] != 'B') return; int totalAngle = 0; int i; for(i=1;i<=3;i++) { switch(path[pathLength-i]) { case 'R': totalAngle += 90; break; case 'L': totalAngle += 270; break; case 'B': totalAngle += 180; break; } } // Get the angle as a number between 0 and 360 degrees. totalAngle = totalAngle % 360; // Replace all of those turns with a single one. switch(totalAngle) { case 0: path[pathLength - 3] = 'S'; break; case 90: path[pathLength - 3] = 'R'; break; case 180: path[pathLength - 3] = 'B'; break; case 270: path[pathLength - 3] = 'L'; break; } // The path is now two steps shorter. pathLength -= 2; }
Langkah 8: Pass Kedua: memecahkan Labirin secepat mungkin!
Program utama: loop () sederhana seperti itu:
void loop() { ledBlink(1); readLFSsensors(); mazeSolve(); // First pass to solve the maze ledBlink(2); while (digitalRead(buttonPin) { } pathIndex = 0; status = 0; mazeOptimization(); // Second Pass: run the maze as fast as possible ledBlink(3); while (digitalRead(buttonPin) { } mode = STOPPED; status = 0; // 1st pass pathIndex = 0; pathLength = 0; }
Jadi, ketika Pass Pertama berakhir, yang harus kita lakukan hanyalah memberi robot array jalur yang dioptimalkan. Robot akan mulai berjalan dan ketika persimpangan ditemukan, sekarang akan menentukan apa yang harus dilakukan berdasarkan apa yang disimpan di path[] .
void mazeOptimization (void) { while (!status) { readLFSsensors(); switch (mode) { case FOLLOWING_LINE: followingLine(); break; case CONT_LINE: if (pathIndex >= pathLength) mazeEnd (); else {mazeTurn (path[pathIndex]); pathIndex++;} break; case LEFT_TURN: if (pathIndex >= pathLength) mazeEnd (); else {mazeTurn (path[pathIndex]); pathIndex++;} break; case RIGHT_TURN: if (pathIndex >= pathLength) mazeEnd (); else {mazeTurn (path[pathIndex]); pathIndex++;} break; } } }
Untuk memerintahkan apa yang harus dilakukan, fungsi baru mazeTurn(path[]) dibuat. Fungsi mazeTurn (path[]) akan menjadi:
void mazeTurn (char dir) { switch(dir) { case 'L': // Turn Left goAndTurn (LEFT, 90); break; case 'R': // Turn Right goAndTurn (RIGHT, 90); break; case 'B': // Turn Back goAndTurn (RIGHT, 800); break; case 'S': // Go Straight runExtraInch(); break; } }
Pass Kedua selesai! Video di bawah ini menunjukkan contoh lengkap yang dikerjakan di sini, pass pertama dan kedua. Di bawah ini kode Arduino yang digunakan dalam tutorial ini:
Langkah 9: Menggunakan Android untuk pengaturan
Aplikasi Android yang dikembangkan untuk proyek Following Line juga dapat digunakan di sini (jika diperlukan, Aplikasi Android dan kodenya tersedia di: Line Follower Robot - PID Control - Android Setup. Kode Arduino yang disajikan di langkah terakhir sudah termasuk komunikasi dengan perangkat Android. Jika Anda tidak ingin menggunakan aplikasi Android, tidak masalah karena kode adalah 'transparent '.
Saya menggunakan Android banyak selama proyek untuk mengirim data pengujian dari robot ke perangkat menggunakan field 'Message Received '. Beberapa variabel harus didefinisikan dengan baik untuk memastikan robot akan berputar dengan sudut yang benar. Yang terpenting di bawah ini (yang ditulis tebal saya ubah beberapa kali):
const int adj = 0; float adjTurn = 8; int adjGoAndTurn = 800; THRESHOLD = 150 const int power = 250; const int iniMotorPower = 250; int extraInch = 200;
Langkah 10: Kesimpulan
Ini adalah bagian kedua dan terakhir dari proyek kompleks, menjelajahi potensi robot Follower Line, di mana konsep sederhana Kecerdasan Buatan (AI) digunakan untuk memecahkan labirin.
Saya bukan ahli AI dan berdasarkan beberapa informasi yang saya dapatkan dari web, saya memahami bahwa apa yang dilakukan robot kecil kami, Rex, memecahkan labirin dapat dianggap sebagai aplikasi AI. Mari kita lihat 2 sumber di bawah ini:
Dari Wikipedia:
Atau dari makalah universitas ini: "Maze Solving Robot Using Freeduino and LSRB Algorithm International Journal of Modern Engineering Research (IJMER)"
File yang diperbarui untuk proyek ini dapat ditemukan di GITHUB. Semoga saya dapat berkontribusi untuk orang lain mempelajari lebih banyak tentang elektronika, robot, Arduino, dll. Untuk tutorial lainnya, kunjungi Blog saya: MJRoBot.org
Saludos dari selatan dunia!
Terima kasih
Marcelo
Kode
Beberapa cuplikan kode tersedia di bagian bawah proyek, termasuk cuplikan #1, #4, #5, #6, #7, #8, #12, #13, #14, #15, #16, dan #17.
Github
https://github.com/Mjrovai/MJRoBot-Maze-Solver
Skematik
File skematik tersedia di bagian bawah proyek.