Buat Robot LEGO Wall-E dengan Arduino Nano: Panduan Langkah demi Langkah
Komponen dan perlengkapan
LEGO Wall-E
Harus mendapatkan yang bekas karena mereka tidak lagi memproduksinya
×
1
Arduino Nano R3
×
1
Motor DC (umum)
×
2
L298N Dual Motor Controller
×
1
LED Bi-warna
dengan 3 pin
×
1
Sensor inframerah
×
1
Buzzer
Yang dapat memainkan nada berbeda
×
1
Baterai 9V
×
1
Resistor 330 ohm
×
3
Kabel jumper (umum)
×
20
Alat dan mesin yang diperlukan
Pakuin (umum)
Aplikasi dan layanan online
Arduino IDE
Tentang proyek ini
Semua orang tahu film Wall-E (dan jika tidak, pergi dan tonton sekarang!) dan pahlawan kuning yang mencoba membersihkan bumi. Dalam proyek ini, saya menggunakan versi LEGO dari teman kecil kami dan mengajarin cara menghindari halangan. Ini adalah proyek pertama saya dan pengalaman belajar yang bagus untuk memahami dasar-dasar elektronika.
Langkah 1 - Kode
Sebagai pengembang perangkat lunak secara profesional, saya memikirkan apa yang ingin saya lakukan padanya dan memulai dengan kode.
// This program is to control the Wall-E Lego robot. // Wall-E is driving around. When he sees an obstacle, he stops to look around and chooses another path. // Arduino Nano has 21 pins that can be used for digitalRead and digitalWrite // PWM pins 3, 5, 6, 9, 10, 11 can be used for analogWrite // pins 0 and 1 can be used for TTL // pins 2 and 3 can be used for external interrupts // pins 10, 11, 12, 13 support SPI communication // pin 13 can be internal LED // pins 14 to 21 are also analog pins A0 to A7 and can be used for analogRead #define INFRA_RED 9 // can be any pin #define GREEN_LED 7 // can be any pin but needs resistor, maybe 220 Ohm - or the ground pin gets 1 kOhm #define RED_LED 8 // can be any pin but needs resistor, maybe 220 Ohm - or the ground pin gets 1 kOhm #define BUZZER 10 // needs to be PWM pin to set frequency, needs resistor, maybe 1 kOhm // MR is the right motor, ML is the left motor #define MR_1 A1 // can be any pin, so let's make them correspond to the pin numbers on the L289N shield #define MR_2 A2 // can be any pin, so let's make them correspond to the pin numbers on the L289N shield #define MR_ENABLE 5 // needs to be PWM pin for speed control #define ML_1 A3 // can be any pin, so let's make them correspond to the pin numbers on the L289N shield #define ML_2 A4 // can be any pin, so let's make them correspond to the pin numbers on the L289N shield #define ML_ENABLE 6 // needs to be PWM pin for speed control // set his normal speed to maximum const int NORMAL_SPEED = 255; void setup() { // right after pressing the reset button, wait for a bit so we can turn him off without damaging any components through voltage spikes delay(2000); // initialise LEDs and buzzer pinMode(GREEN_LED, OUTPUT); pinMode(RED_LED, OUTPUT); // pinMode(BUZZER, OUTPUT); // not necessary // reset LED to green digitalWrite(RED_LED, LOW); digitalWrite(GREEN_LED, HIGH); // set DC motor pins pinMode(MR_ENABLE, OUTPUT); // motor right pinMode(MR_1, OUTPUT); pinMode(MR_2, OUTPUT); pinMode(ML_ENABLE, OUTPUT); // motor left pinMode(ML_1, OUTPUT); pinMode(ML_2, OUTPUT); // initialise infra red pinMode(INFRA_RED, INPUT); // initialise random number generator for random turns randomSeed(analogRead(0)); // say hello playHello(); } void loop() { // normal operations driveForwards(NORMAL_SPEED); // set LED to green digitalWrite(RED_LED, LOW); digitalWrite(GREEN_LED, HIGH); // check for obstacles if (digitalRead(INFRA_RED) == LOW) { //LOW means obstacle detected // change LED to red digitalWrite(GREEN_LED, LOW); digitalWrite(RED_LED, HIGH); // stop motors stopDriving(); // play uh-oh sound playUhOh(); // check left turnLeft(500); boolean obstacleLeft = false; if (digitalRead(INFRA_RED) == LOW) { obstacleLeft = true; } // turn back to centre delay(100); turnRight(500); // wait a little, we don't want to seem rushed delay(500); // check right turnRight(500); boolean obstacleRight = false; if (digitalRead(INFRA_RED) == LOW) { obstacleRight = true; } // turn back to centre delay(100); turnLeft(500); // now check how to get out of here if (obstacleLeft && obstacleRight) { driveBackwards(NORMAL_SPEED / 3); // beep while going backwards for 5 seconds for (int i = 0; i < 5; i++) { tone(BUZZER, 1000, 500); delay(1000); } // to avoid getting stuck somewhere, randomly turn into a direction before continuing journey randomTurn(800, 1600); } else if (obstacleLeft) { turnRight(1000); } else if (obstacleRight) { turnLeft(1000); } else { randomTurn(1000, 1800); } } // do random stuff for more interaction int number = random(100); // creates a random number between 0 and 99 if (number == 0) { randomTurn(200,2000); } } void driveForwards(int speed) { // set the motors to go in the same direction digitalWrite(MR_1, LOW); digitalWrite(MR_2, HIGH); digitalWrite(ML_1, HIGH); digitalWrite(ML_2, LOW); setSpeed(speed); } void driveBackwards(int speed) { // set the motors to go in the opposite direction digitalWrite(MR_1, HIGH); digitalWrite(MR_2, LOW); digitalWrite(ML_1, LOW); digitalWrite(ML_2, HIGH); setSpeed(speed); } void turnLeft(int duration) { // turn left by going forwards with the right wheel and backwards with the left wheel digitalWrite(MR_1, HIGH); digitalWrite(MR_2, LOW); digitalWrite(ML_1, HIGH); digitalWrite(ML_2, LOW); // slow down to turn setSpeed(NORMAL_SPEED / 2); delay(duration); stopDriving(); } void turnRight(int duration) { // turn right by going backwards with the right wheel and forwards with the left wheel digitalWrite(MR_1, LOW); digitalWrite(MR_2, HIGH); digitalWrite(ML_1, LOW); digitalWrite(ML_2, HIGH); // slow down to turn setSpeed(NORMAL_SPEED / 2); delay(duration); stopDriving(); } void stopDriving() { // turn off all the motor pins digitalWrite(MR_1, LOW); digitalWrite(MR_2, LOW); digitalWrite(ML_1, LOW); digitalWrite(ML_2, LOW); // not sure what to do with the ENABLE pins, but doesn't hurt to turn them off as well I guess digitalWrite(MR_ENABLE, LOW); digitalWrite(ML_ENABLE, LOW); } void setSpeed(int speed) { // speed must be between 0 and 255 speed = constrain(speed, 0, 255); // set the speed to turn the motors on analogWrite(MR_ENABLE, speed); analogWrite(ML_ENABLE, speed); } void randomTurn(int minimum, int maximum) { unsigned long time = millis(); int duration = random(minimum, maximum); if (time % 2) { turnRight(duration); } else { turnLeft(duration); } } void playHello() { tone(BUZZER, 262, 250); // plays C4 delay(300); tone(BUZZER, 330, 250); // plays E4 delay(300); tone(BUZZER, 392, 250); // plays G4 delay(300); tone(BUZZER, 523, 500); // plays C5 delay(550); } void playUhOh() { tone(BUZZER, 523, 250); // plays C5 delay(300); tone(BUZZER, 415, 500); // plays Gis4 delay(600); }
Saat Anda memutuskan koneksi motor yang berjalan, dapat terjadi lonjakan tegangan yang dapat merusak elektronik Anda. Oleh karena itu, saya membuat Wall-E menunggu dua detik sebelum melakukan apa pun. Artinya saya hanya dapat menekan tombol Reset pada Arduino dan dengan cepat memutuskan baterai tanpa merusak apa pun.
Dia memainkan sedikit melodi saat bangun dan kemudian mulai berkendara. Ketika dia melihat halangan, dia berhenti, memainkan suara “Uh-oh”, dan melihat sekeliling untuk menentukan jalur terbaik. Jenis sensor inframerah yang saya gunakan memiliki sekrup kecil di bagian belakang yang memungkinkan Anda menentukan jarak di mana ia menghasilkan sinyal. Itulah sebabnya tidak ada perhitungan jarak dalam kode. (Saya ingin menggunakan sensor ultrasonik terlebih dahulu, tetapi tidak cocok dengan matanya.)
Wall-E pertama kali memeriksa apakah sisi kiri bersih, dan kemudian apakah sisi kanan bersih. Jika kedua sisi terhalang, dia mundur sambil berbunyi seperti mesin berat di lokasi konstruksi, dan kemudian berbelok ke arah acak dan melanjutkan. Jika hanya satu sisi yang terhalang, dia melanjutkan ke sisi lain. Jika kedua sisi bebas, dia memilih satu secara acak dan melanjutkan perjalanan.
Saya mencoba membuatnya melakukan berbelok acak, tetapi bagian itu belum selesai. Saya mencoba menggunakan timer bawaan Arduino. Beritahu saya di komentar jika Anda memiliki ide untuk mengoptimalkannya!
Langkah 2 - Menghubungkan kabel
Hal pertama adalah memasang sensor inframerah ke dalam mata sehingga tidak terlalu terlihat. Saya membocornya, menempelkan pin LEGO pada sensor (supaya matanya dapat bergerak ke atas dan ke bawah) dan kemudian menggunakan blue-tack untuk meletakkan potongan LEGO kembali di sekitar sensor:
Hal terpenting tentang motor adalah mereka memiliki torsi yang cukup, karena pengaturan roda Wall-E membutuhkan cukup banyak gaya untuk bergerak. Saya harus menempelkan kabel pada motor dan memasangnya dengan cara yang terhubung secara aman ke LEGO. Jadi saya membocorkan rodanya, memesan satu kantong penuh pin LEGO Technic, membalut selang tape (apakah begitu Anda memanggilnya? Seperti tape lembut yang dapat ditempelkan pada kulit) di sekitar poros motor, dan menempelkannya ke dua pin yang menjadi poros utama untuk setiap roda. Ini bekerja selama beberapa menit, tetapi kemudian gesekan terlalu tinggi untuk lem pada tape untuk memegang. Untungnya, pin Technic memiliki ranuran kecil di sisi, jadi tape memiliki tempat untuk memegang, yang mereka lakukan dengan senang hati setelah direndam dalam lem super.
Saya juga membocorkan sedikit dadanya untuk menempelkan LED melalui. Kemudian saya menghubungkan semua bagian dan Arduino.
Motor shield hanya muat di perutnya:
Diagramnya juga tidak terlalu jelas, tetapi saya mencoba mengkodekan kabel dengan warna untuk gambaran yang lebih baik:
Menurut konvensi, semua kabel merah positif (“mengirimi” listrik) dan semua kabel hitam negatif (“menerima” listrik). Kabel kuning di pojok kanan atas membawa sinyal untuk sensor inframerah; kabel oranye dan hijau untuk LED bi-warna tiga pin, kabel ungu untuk memberitahu motor shield arah mana motor harus berputar, dan kabel biru untuk memberitahu motor shield secepat mana motor harus berputar.
Motor shield memiliki tutorial yang sangat baik yang membuatnya mudah untuk dihubungkan dan digunakan. Sayangnya, bagian Fritzing tidak memiliki dua pin untuk pengaturan kecepatan, jadi kabel biru secara acak berakhir di motor shield dalam diagram.
Salah satu masalah yang saya hadapi saat memasang semuanya adalah kurangnya pin Voltage dan Ground. Saya ingin menyediakan daya langsung ke motor melalui motor shield sehingga mereka dapat mendapatkan sejumlah besar daya, tetapi saya harus menyediakan 5V ke Arduino dan sensor inframerah juga. Jadi saya melakukan apa yang hampir semua orang di internet bilang jangan lakukan: saya menghubungkan output 5V dari motor shield ke pin 5V Arduino sebagai input. Dengan shield yang saya gunakan, saya dapat yakin bahwa ia mengeluarkan 5V yang terregulasi tanpa lonjakan yang dapat merusak Arduino Anda. Jika Anda menyambungkan sumber daya yang tidak terregulasi ke pin itu, Anda mungkin akan merusak sesuatu. Saya ingin menggunakan pin Vin pada awalnya, tetapi pin itu memiliki mekanisme bawaan yang menurunkan segalanya, jadi 5V saya akan menjadi 3.8V atau sekitarnya, yang tidak cukup untuk Arduino berfungsi dengan baik. Sebaliknya, saya menggunakan Vin bebas untuk menyediakan daya(!) sensor inframerah dengan 5V, karena saya tidak memiliki pemisah kabel, dan saya tahu akan ada 5V yang keluar dari sana juga. Yeah, mulai terasa sedikit seperti Frankenstein pada titik ini. Tapi itu bekerja!
Langkah 3 - Wall-E dalam Aksi
Berikut beberapa video yang menunjukkan dia dalam aksi:
Dan di sini saya mencoba apa yang akan dilakukan jika dia terjebak di sudut:
Jadi inilah proyek kecil pertama saya. Saya sekarang berencana untuk mengoptimalkan koneksi kabel dan mungkin menambahkan servo motor sehingga dia dapat memutar kepalanya. Saya mungkin bahkan akan membeli pemisah dan motor shield serta papan yang lebih kecil sehingga saya dapat memasang semuanya di perutnya.
This is the central control file for Wall-E. It is basic, but all he needs at the moment.
// This program is to control the Wall-E Lego robot. // Wall-E is driving around. When he sees an obstacle, he stops to look around and chooses another path. // Arduino Nano has 21 pins that can be used for digitalRead and digitalWrite // PWM pins 3, 5, 6, 9, 10, 11 can be used for analogWrite // pins 0 and 1 can be used for TTL // pins 2 and 3 can be used for external interrupts // pins 10, 11, 12, 13 support SPI communication // pin 13 can be internal LED // pins 14 to 21 are also analog pins A0 to A7 and can be used for analogRead #define INFRA_RED 9 // can be any pin #define GREEN_LED 7 // can be any pin but needs resistor, maybe 220 Ohm - or the ground pin gets 1 kOhm #define RED_LED 8 // can be any pin but needs resistor, maybe 220 Ohm - or the ground pin gets 1 kOhm #define BUZZER 10 // needs to be PWM pin to set frequency, needs resistor, maybe 1 kOhm // MR is the right motor, ML is the left motor #define MR_1 A1 // can be any pin, so let's make them correspond to the pin numbers on the L289N shield #define MR_2 A2 // can be any pin, so let's make them correspond to the pin numbers on the L289N shield #define MR_ENABLE 5 // needs to be PWM pin for speed control #define ML_1 A3 // can be any pin, so let's make them correspond to the pin numbers on the L289N shield #define ML_2 A4 // can be any pin, so let's make them correspond to the pin numbers on the L289N shield #define ML_ENABLE 6 // needs to be PWM pin for speed control // set his normal speed to maximum const int NORMAL_SPEED = 255; void setup() { // right after pressing the reset button, wait for a bit so we can turn him off without damaging any components through voltage spikes delay(2000); // initialise LEDs and buzzer pinMode(GREEN_LED, OUTPUT); pinMode(RED_LED, OUTPUT); // pinMode(BUZZER, OUTPUT); // not necessary // reset LED to green digitalWrite(RED_LED, LOW); digitalWrite(GREEN_LED, HIGH); // set DC motor pins pinMode(MR_ENABLE, OUTPUT); // motor right pinMode(MR_1, OUTPUT); pinMode(MR_2, OUTPUT); pinMode(ML_ENABLE, OUTPUT); // motor left pinMode(ML_1, OUTPUT); pinMode(ML_2, OUTPUT); // initialise infra red pinMode(INFRA_RED, INPUT); // initialise random number generator for random turns randomSeed(analogRead(0)); // say hello playHello(); } void loop() { // normal operations driveForwards(NORMAL_SPEED); // set LED to green digitalWrite(RED_LED, LOW); digitalWrite(GREEN_LED, HIGH); // check for obstacles if (digitalRead(INFRA_RED) == LOW) { //LOW means obstacle detected // change LED to red digitalWrite(GREEN_LED, LOW); digitalWrite(RED_LED, HIGH); // stop motors stopDriving(); // play uh-oh sound playUhOh(); // check left turnLeft(500); boolean obstacleLeft = false; if (digitalRead(INFRA_RED) == LOW) { obstacleLeft = true; } // turn back to centre delay(100); turnRight(500); // wait a little, we don't want to seem rushed delay(500); // check right turnRight(500); boolean obstacleRight = false; if (digitalRead(INFRA_RED) == LOW) { obstacleRight = true; } // turn back to centre delay(100); turnLeft(500); // now check how to get out of here if (obstacleLeft && obstacleRight) { driveBackwards(NORMAL_SPEED / 3); // beep while going backwards for 5 seconds for (int i = 0; i < 5; i++) { tone(BUZZER, 1000, 500); delay(1000); } // to avoid getting stuck somewhere, randomly turn into a direction before continuing journey randomTurn(800, 1600); } else if (obstacleLeft) { turnRight(1000); } else if (obstacleRight) { turnLeft(1000); } else { randomTurn(1000, 1800); } } // do random stuff for more interaction int number = random(100); // creates a random number between 0 and 99 if (number == 0) { randomTurn(200,2000); } } void driveForwards(int speed) { // set the motors to go in the same direction digitalWrite(MR_1, LOW); digitalWrite(MR_2, HIGH); digitalWrite(ML_1, HIGH); digitalWrite(ML_2, LOW); setSpeed(speed); } void driveBackwards(int speed) { // set the motors to go in the opposite direction digitalWrite(MR_1, HIGH); digitalWrite(MR_2, LOW); digitalWrite(ML_1, LOW); digitalWrite(ML_2, HIGH); setSpeed(speed); } void turnLeft(int duration) { // turn left by going forwards with the right wheel and backwards with the left wheel digitalWrite(MR_1, HIGH); digitalWrite(MR_2, LOW); digitalWrite(ML_1, HIGH); digitalWrite(ML_2, LOW); // slow down to turn setSpeed(NORMAL_SPEED / 2); delay(duration); stopDriving(); } void turnRight(int duration) { // turn right by going backwards with the right wheel and forwards with the left wheel digitalWrite(MR_1, LOW); digitalWrite(MR_2, HIGH); digitalWrite(ML_1, LOW); digitalWrite(ML_2, HIGH); // slow down to turn setSpeed(NORMAL_SPEED / 2); delay(duration); stopDriving(); } void stopDriving() { // turn off all the motor pins digitalWrite(MR_1, LOW); digitalWrite(MR_2, LOW); digitalWrite(ML_1, LOW); digitalWrite(ML_2, LOW); // not sure what to do with the ENABLE pins, but doesn't hurt to turn them off as well I guess digitalWrite(MR_ENABLE, LOW); digitalWrite(ML_ENABLE, LOW); } void setSpeed(int speed) { // speed must be between 0 and 255 speed = constrain(speed, 0, 255); // set the speed to turn the motors on analogWrite(MR_ENABLE, speed); analogWrite(ML_ENABLE, speed); } void randomTurn(int minimum, int maximum) { unsigned long time = millis(); int duration = random(minimum, maximum); if (time % 2) { turnRight(duration); } else { turnLeft(duration); } } void playHello() { tone(BUZZER, 262, 250); // plays C4 delay(300); tone(BUZZER, 330, 250); // plays E4 delay(300); tone(BUZZER, 392, 250); // plays G4 delay(300); tone(BUZZER, 523, 500); // plays C5 delay(550); } void playUhOh() { tone(BUZZER, 523, 250); // plays C5 delay(300); tone(BUZZER, 415, 500); // plays Gis4 delay(600); }
Skematik
Arti warna kabel: merah = tegangan (positif) hitam = ground (negatif) kuning = sinyal untuk sensor inframerah oranye dan hijau = koneksi untuk input LED merah dan hijau ungu = kontrol arah motor biru = kontrol kecepatan motor (sayangnya, bagian Fritzing tidak memiliki dua pin yang dimiliki oleh motor bridge saya untuk koneksi ini, jadi terlihat seperti kabel longgar saat ini)wall-e2_3P6X71BCnP.fzz