Manufaktur industri
Industri Internet of Things | bahan industri | Pemeliharaan dan Perbaikan Peralatan | Pemrograman industri |
home  MfgRobots >> Manufaktur industri >  >> Manufacturing Technology >> Proses manufaktur

MobBob:Robot Arduino DIY Dikendalikan oleh Smartphone Android

Komponen dan persediaan

Arduino Nano R3
× 1
Modul Bluetooth HC-05
× 1
Motor servo mikro SG90
× 4
tempat baterai 4xAA
× 1
Baterai AA
× 4

Alat dan mesin yang diperlukan

Besi solder (generik)
Printer 3D (generik)

Aplikasi dan layanan online

Arduino IDE

Tentang proyek ini

Saya membuat robot ini sesuai dengan instruksi di situs web. Ide bagus untuk simbiosis antara Arduino dan Android.

MobBob adalah robot yang dikendalikan smartphone. Dengan memanfaatkan kecanggihan ponsel pintar Anda, MobBob adalah robot berjalan dan berbicara dengan pengenalan suara dan visi komputer.

Bagian cetakan 3D:https://www.thingiverse.com/thing:715688

File Android.apk:https://apkpure.com/mobbob/com.cevinius.MobBob

Dalam kode Anda ingin:

- Perbarui variabel pin agar sesuai dengan build Anda

- Tweak pusat servo, nilai min dan max

- Setel "FRONT_JOINT_HIPS" ke 1 atau -1 tergantung di mana servo pinggul Anda dipasang. Saya memasangnya dengan poros servo di bagian depan MobBob. Untuk konfigurasi ini, setel nilai ini ke 1.

Kode

  • kode
kodeArduino
/* * =============================================================* MobBob Control Program - Software Serial Bluetooth Version * oleh Kevin Chan (alias Cevinius) * =============================================================* * Program ini memungkinkan MobBob dikendalikan menggunakan perintah serial. Dalam versi kode ini, perintah * diterima melalui port serial perangkat lunak, dengan pin yang ditentukan di #define di dekat bagian atas. * Ini berarti Anda dapat menggunakan papan Arduino apa pun yang kompatibel, dan mencolokkan kartu bluetooth ke pin yang disetel untuk * serial perangkat lunak. (Berbeda dengan versi lain dari ini yang dirancang untuk papan Bluno dari DFRobot.) * * Program ini panjang dan berisi 2 komponen utama - program animasi servo yang halus dan program pengurai perintah * serial. * * Sistem Animasi * ================* Program animasi dirancang untuk menganimasikan array keyframe servo dengan lancar. Kode mencoba melakukan * yang terbaik agar mudah digunakan. * * Sistem animasi hanya akan mengantri 1 perintah. yaitu Satu perintah dapat dijalankan, * dan satu perintah dapat diantrekan. Jika Anda mengirim lebih banyak perintah, mereka akan menimpa perintah yang diantrekan. * * Sistem animasi secara default akan menunggu untuk menyelesaikan animasi saat ini sebelum memulai yang berikutnya. Ini * berarti bahwa jika data animasi diakhiri dengan robot dalam pose dasarnya, semuanya akan bergabung dengan lancar. Untuk *mendukung hal tersebut, sistem animasi juga memiliki fitur dimana suatu animasi dapat memiliki “finish sequence”* untuk menempatkan robot kembali ke pose dasar. Fitur ini digunakan untuk animasi berjalan maju/mundur. * Animasi tersebut memiliki urutan akhir yang menempatkan robot kembali ke pose dasar. * * Saat animasi selesai diputar, sistem animasi akan menampilkan string respons ke port Serial. * Ini memungkinkan penelepon untuk mengetahui kapan animasi yang mereka minta telah selesai diputar. Ini berguna * bagi pengguna untuk mengurutkan animasi - menunggu satu selesai sebelum memulai yang lain. * * Kode animasi memiliki banyak variabel untuk memungkinkan hal-hal yang akan di-tweak. Misalnya. Perbarui frekuensi, pin arduino, dll. * * Format array data animasi juga dirancang agar mudah diedit dengan tangan. * * Command Parser * ==============* Sistem ini mem-parsing perintah yang diterima melalui serial, dan memprosesnya. Perintah termasuk satu untuk secara langsung * mengatur posisi servo, serta perintah untuk memicu animasi dan jalan yang telah ditentukan sebelumnya. * * Jadi, pengguna yang tidak ingin khawatir tentang detail berjalan cukup menggunakan jalan/animasi yang telah ditentukan. * Dan, pengguna yang ingin kontrol penuh atas servos (untuk membuat animasi baru dengan cepat) dapat melakukannya juga. * * Seperti disebutkan di atas, perintah ini dapat digunakan secara interaktif dari Arduino Serial Monitor. Mereka juga dapat * dikirim menggunakan Bluetooth LE (bila Bluno digunakan). Aplikasi telepon akan mengirimkan perintah melalui Bluetooth LE ke * Bluno. * * Perintah Umum:* ----------------- * Siap/OK Periksa: * Pemeriksaan status. Respons segera dikembalikan untuk memeriksa apakah pengontrol berfungsi. * * Atur Servo: * waktu - waktu untuk tween ke sudut yang ditentukan, 0 akan langsung melompat ke sudut * LeftHip - mikrodetik dari pusat. -ve adalah pinggul masuk, +ve adalah pinggul keluar * Kaki kiri - mikrodetik dari datar. -ve adalah kaki ke bawah, +ve adalah kaki ke atas * rightHip - mikrodetik dari pusat. -ve adalah pinggul masuk, +ve adalah pinggul keluar * RightFoot - mikrodetik dari datar. -ve adalah kaki ke bawah, +ve adalah kaki ke atas * Perintah ini digunakan untuk mendapatkan kontrol penuh atas servos. Anda dapat mengubah robot dari * pose saat ini ke pose yang ditentukan selama durasi yang ditentukan. * * Stop/Reset: * Menghentikan robot setelah animasi saat ini. Dapat digunakan untuk menghentikan animasi yang disetel ke loop * tanpa batas. Ini juga dapat digunakan untuk menempatkan robot ke dalam pose dasarnya (berdiri tegak) * * Berhenti Segera: * Menghentikan robot segera tanpa menunggu untuk menyelesaikan animasi saat ini. Ini * menginterupsi animasi robot saat ini. Berpotensi robot bisa menjadi mid-animation* dan dalam pose yang tidak stabil, jadi berhati-hatilah saat menggunakan ini. * * Perintah Berjalan Standar:* ----------------------- * Maju:, -1 berarti kontinu, 0 atau tidak ada param sama dengan 1 kali. * Mundur:, -1 artinya kontinu, 0 atau tidak ada param sama dengan 1 kali. * Belok Kiri:, -1 artinya kontinu, 0 atau tidak ada param sama dengan 1 kali. * Belok Kanan:, -1 artinya terus menerus, 0 atau tidak ada param sama dengan 1 kali. * * Perintah Animasi Menyenangkan:* ----------------------- * Shake Head:, -1 berarti kontinu, 0 atau tanpa param sama dengan 1 kali. * * Bounce:, -1 artinya kontinu, 0 atau tidak ada param sama dengan 1 kali. * * Goyangan:, -1 artinya kontinu, 0 atau tidak ada param sama dengan 1 kali. * Goyangan Kiri:, -1 artinya kontinu, 0 atau tidak ada param sama dengan 1 kali. * Goyangan Kanan:, -1 artinya kontinu, 0 atau tidak ada param sama dengan 1 kali. * * Tap Feet:, -1 artinya terus menerus, 0 atau tidak ada param sama dengan 1 kali. * Tap Left Foot:, -1 artinya terus menerus, 0 atau tidak ada param sama dengan 1 kali. * Tap Right Foot:, -1 artinya terus menerus, 0 atau tidak ada param sama dengan 1 kali. * * Goyangkan Kaki:, -1 artinya terus menerus, 0 atau tidak ada param sama dengan 1 kali. * Goyangkan Kaki Kiri:, -1 artinya terus menerus, 0 atau tidak ada param sama dengan 1 kali. * Goyangkan Kaki Kanan:, -1 artinya terus menerus, 0 atau tidak ada param sama dengan 1 kali. * * Juga, kode akan mengirim string respons kembali melalui Serial ketika perintah telah selesai * dijalankan. * * Jika perintah selesai secara normal, string respons adalah kode perintah tanpa parameter *. Misalnya. Setelah selesai bergerak maju, ia akan mengirimkan respons "". * * Jika sebuah perintah diinterupsi dengan , animasi saat ini mungkin telah dihentikan di tengah jalan. * Dalam hal ini, robot mungkin berada dalam pose tengah jalan yang aneh, dan finishAnims mungkin tidak * dimainkan. Untuk memberi tahu pengguna bahwa ini telah terjadi, string respons akan memiliki parameter * -1. Misalnya, jika suatu jalan dihentikan di tengah jalan menggunakan , string responsnya adalah *  untuk menunjukkan bahwa jalan tersebut telah berhenti, tetapi dihentikan di tengah jalan. * (Catatan:Jika Anda menggunakan  untuk berhenti, itu akan menunggu siklus animasi saat ini selesai * sebelum berhenti. Jadi, animasi tidak akan berhenti di tengah jalan dalam kasus itu.) * * Karena tanggapan dikirim setelah animasi selesai, pengirim perintah dapat * mencari string respons untuk menentukan kapan robot siap untuk perintah baru. * Misalnya Jika Anda menggunakan perintah , string respons tidak akan dikirim sampai semua 3 langkah * (dan selesai anim) selesai. Jadi, pengirim perintah dapat menunggu string respons * sebelum memberi tahu robot untuk melakukan hal berikutnya. */ #include #include //-------------------------------- -------------------------------------------------- // Kecepatan komunikasi serial - Atur ini untuk kartu serial (bluetooth) Anda.//------------------------------- -------------------------------------------------- -// Kecepatan komunikasi serial dengan papan bluetooth.// Beberapa papan default ke 9600. Papan yang saya miliki memiliki nilai default 115200.#define SERIAL_SPEED 115200// Siapkan port Serial Perangkat Lunak pada pin ini.const int rxPin =11; // pin yang digunakan untuk menerima dataconst int txPin =12; // pin digunakan untuk mengirim dataSoftwareSerial softwareSerial(rxPin, txPin);//---------------------------------- ------------------------------------------------// Setup Pin Arduino - Atur ini untuk robot khusus Anda.//------------------------------------------------ --------------------------------------------- const int SERVO_LEFT_HIP =5;const int SERVO_LEFT_FOOT =2;const int SERVO_RIGHT_HIP =3;const int SERVO_RIGHT_FOOT =4;// Saya ingin kode ini dapat digunakan pada semua biped 4-servo! (Seperti Bob, MobBob)// Saya perhatikan bahwa beberapa build memasang servos pinggul menghadap ke cara yang berbeda// seperti yang saya lakukan pada MobBob, jadi, pengaturan ini memungkinkan Anda mengonfigurasi kode// untuk salah satu gaya build.// 1 untuk gaya MobBob pinggul menghadap ke depan (sendi ke depan)// -1 untuk gaya Bob pinggul menghadap ke belakang (sendi ke belakang)#define FRONT_JOINT_HIPS 1//------------------- -------------------------------------------------- -------------// Konstanta Servo Max/Min/Centre - Tetapkan ini untuk robot khusus Anda.//------------------ -------------------------------------------------- --------------const int LEFT_HIP_CENTRE =1580;const int LEFT_HIP_MIN =LEFT_HIP_CENTRE - 500;const int LEFT_HIP_MAX =LEFT_HIP_CENTRE + 500;const int LEFT_FOOT_CENTRE =1410;const_FOOTRE_FOOT_CENTRE LEFT; const int LEFT_FOOT_MAX =LEFT_FOOT_CENTRE + 500;const int RIGHT_HIP_CENTRE =1500;const int RIGHT_HIP_MIN =RIGHT_HIP_CENTRE - 500;const int RIGHT_HIP_MAX =RIGHT_HIP_CENTRE + 500;const int RIGHT_FO 465;const int RIGHT_FOOT_MIN =RIGHT_FOOT_CENTRE - 500;const int RIGHT_FOOT_MAX =RIGHT_FOOT_CENTRE + 500;//------------------------------ ------------------------------------------------// Helper berfungsi untuk membantu menghitung nilai gabungan dengan cara yang lebih mudah digunakan.// Anda dapat menyesuaikan tanda di sini jika servos diatur dengan cara yang berbeda.// Memperbarui di sini berarti data animasi tidak perlu diubah jika // servo diatur secara berbeda.// (Misalnya Servo pinggul Bob asli mundur ke MobBob.)//// (Juga, saya merasa sulit untuk mengingat tanda-tanda yang digunakan untuk setiap servo karena mereka // berbeda untuk pinggul kiri/kanan, dan untuk kaki kiri/kanan.) //------------------------------------------------ ------------------------------int LeftHipCentre() { kembalikan LEFT_HIP_CENTRE; }int LeftHipIn(int milidetik) { kembali LEFT_HIP_CENTRE + (FRONT_JOINT_HIPS * milidetik); }int LeftHipOut(int milidetik) { kembali LEFT_HIP_CENTRE - (FRONT_JOINT_HIPS * milidetik); }int RightHipCentre() { kembalikan RIGHT_HIP_CENTRE; }int RightHipIn(int milidetik) { return RIGHT_HIP_CENTRE - (FRONT_JOINT_HIPS * milidetik); }int RightHipOut(int milidetik) { return RIGHT_HIP_CENTRE + (FRONT_JOINT_HIPS * milidetik); }int LeftFootFlat() { kembali LEFT_FOOT_CENTRE; }int LeftFootUp(int milidetik) { kembali LEFT_FOOT_CENTRE - milidetik; }int LeftFootDown(int milidetik) { kembali LEFT_FOOT_CENTRE + milidetik; }int RightFootFlat() { kembalikan RIGHT_FOOT_CENTRE; }int RightFootUp(int milidetik) { return RIGHT_FOOT_CENTRE + milidetik; }int RightFootDown(int milidetik) { return RIGHT_FOOT_CENTRE - milidetik; }//----------------------------------------------------------- -----------------------------------// Data animasi keyframe untuk gaya berjalan standar dan animasi servo lainnya// // Formatnya adalah { , ​​, , ,  }// milidetik - waktu untuk tween ke posisi keyframe ini. Misalnya. 500 berarti butuh 500 ms untuk berpindah dari// posisi robot di awal bingkai ini ke posisi yang ditentukan dalam bingkai ini// leftHipMicros - posisi pinggul kiri dalam mikrodetik servo.// LeftFootMicros - posisi pinggul kiri di servo microsecs.// rightHipMicros - posisi pinggul kiri dalam mikrodetik servo.// RightFootMicros - posisi pinggul kiri dalam mikrodetik servo.// // Nilai mikro servo, mendukung nilai khusus -1. Jika nilai ini diberikan, ia memberitahu// kode animasi untuk mengabaikan servo ini di keyframe ini. yaitu Servo itu akan// tetap pada posisinya di awal keyframe ini.//// Juga, elemen pertama dalam data animasi adalah khusus. Ini adalah elemen metadata.// Elemen pertama adalah { , 0, 0, 0, 0 }, yang memberitahu kita jumlah frame// dalam animasi. Jadi, keyframe pertama sebenarnya ada di animData[1], dan keyframe terakhir// ada di animData[]. (Di mana  adalah nilai dalam animData[0][0].)//----------------------------- -------------------------------------------------- ---// Konstanta untuk membuat pengaksesan array keyframe lebih mudah dibaca manusia.const int TWEEN_TIME_VALUE =0;const int LEFT_HIP_VALUE =1;const int LEFT_FOOT_VALUE =2;const int RIGHT_HIP_VALUE =3;const int RIGHT_FOOT_VALUE =4;// Konstanta yang digunakan dalam animasi kiprah berjalan data.const int FOOT_DELTA =150;const int HIP_DELTA =FRONT_JOINT_HIPS * 120;// Beralih ke posisi berdiri tegak default. Digunakan oleh stopAnim().int standStraightAnim[][5] ={ // Metadata. Elemen pertama adalah jumlah frame. { 1, 0, 0, 0, 0 }, // Feet flat, Feet even { 300, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() }};// Sebelum ini, perintahkan robot untuk Kaki Rata, Kaki Rata (yaitu standStraightAnim).int walkForwardAnim[][5] ={ // Metadata. Elemen pertama adalah jumlah frame. { 8, 0, 0, 0, 0 }, // Miringkan ke kiri, Kaki genap { 300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA) }, // Miringkan ke kiri, Kaki kanan maju { 300, LeftHipIn(HIP_DELTA), LeftFootUp(FOOT_DELTA), RightHipOut(HIP_DELTA), RightFootDown(FOOT_DELTA) }, // Kaki rata, Kaki kanan ke depan { 300, LeftHipIn(HIP_DELTA), LeftFootFlat(), RightHipOut(HIP_DELTA), RightFootFlat() }, // Miringkan ke kanan, Kaki kanan ke depan { 300, LeftHipIn(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipOut(HIP_DELTA), RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Kaki genap { 300, LeftHipCentre (), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Kaki kiri ke depan { 300, LeftHipOut(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootUp(FOOT_DELTA) , // Kaki rata, Kaki kiri ke depan { 300, LeftHipOut(HIP_DELTA), LeftFootFlat(), RightHipIn(HIP_DELTA), RightFootFlat() }, // Miringkan ke kiri, Kaki kiri ke depan { 300, LeftHipOut(HIP_DEL TA), LeftFootUp(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA) }};// Sebelum ini, buat robot ke Kaki Rata, Kaki Genap (mis. standStraightAnim).int walkBackwardAnim[][5] ={ // Metadata. Elemen pertama adalah jumlah frame. { 8, 0, 0, 0, 0 }, // Miringkan ke kiri, Kaki genap { 300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA) }, // Miringkan ke kiri, Kaki kiri maju { 300, LeftHipOut(HIP_DELTA), LeftFootUp(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA) }, // Kaki rata, Kaki kiri ke depan { 300, LeftHipOut(HIP_DELTA), LeftFootFlat(), RightHipIn(HIP_DELTA), RightFootFlat() }, // Miringkan ke kanan, Kaki kiri ke depan { 300, LeftHipOut(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Kaki genap { 300, LeftHipCentre (), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Kaki kanan ke depan { 300, LeftHipIn(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipOut(HIP_DELTA), RightFootUp(FOOT_DELTA) , // Kaki rata, Kaki kanan ke depan { 300, LeftHipIn(HIP_DELTA), LeftFootFlat(), RightHipOut(HIP_DELTA), RightFootFlat() }, // Miringkan ke kiri, Kaki kanan ke depan { 300, LeftHipIn(HIP_DELTA ), LeftFootUp(FOOT_DELTA), RightHipOut(HIP_DELTA), RightFootDown(FOOT_DELTA) }};// Finish walk anim membawa robot dari ujung walkForwardAnim/walkBackwardAnim kembali ke standStraightAnim.int walkEndAnim[][5] ={ // Metadata . Elemen pertama adalah jumlah frame. { 2, 0, 0, 0, 0 }, // Miringkan ke kiri, Kaki genap { 300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA) }, // Feet flat, Feet even { 300, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() }};// Sebelum ini, bawa robot ke Feet Flat, Feet Even (yaitu standStraightAnim).int turnLeftAnim[][5] ={ / / Metadata. Elemen pertama adalah jumlah frame. { 6, 0, 0, 0, 0 }, // Miringkan ke kiri, Kaki genap { 300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA) }, // Miringkan ke kiri, Belok kiri pinggul, Belok pinggul kanan { 300, LeftHipIn(HIP_DELTA), LeftFootUp(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA) }, // Kaki rata, Belok kiri pinggul, Belok pinggul kanan { 300, LeftHipIn(HIP_DELTA), LeftFootFlat (), RightHipIn(HIP_DELTA), RightFootFlat() }, // Miringkan ke kanan, Belok kiri pinggul, Belok pinggul kanan { 300, LeftHipIn(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Kaki genap { 300, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Feet flat, Feet even { 300, LeftHipCentre(), LeftFootFlat(), RightHipCentre( ), RightFootFlat() }};// Sebelum ini, buat robot ke Feet Flat, Feet Even (yaitu standStraightAnim).int turnRightAnim[][5] ={ // Metadata. Elemen pertama adalah jumlah frame. { 6, 0, 0, 0, 0 }, // Miringkan ke kanan, Kaki genap { 300, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Belok kiri pinggul, Belok pinggul kanan { 300, LeftHipIn(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootUp(FOOT_DELTA) }, // Kaki rata, Belok kiri pinggul, Belok pinggul kanan { 300, LeftHipIn(HIP_DELTA), LeftFootFlat (), RightHipIn(HIP_DELTA), RightFootFlat() }, // Miringkan ke kiri, Belok kiri pinggul, Belok pinggul kanan { 300, LeftHipIn(HIP_DELTA), LeftFootUp(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA) }, // Miringkan ke kiri, Kaki genap { 300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA) }, // Feet flat, Feet even { 300, LeftHipCentre(), LeftFootFlat(), RightHipCentre( ), RightFootFlat() }};// Goyangan kepala animasi. Kiri kanan dengan cepat untuk meniru shakehead.int shakeHeadAnim[][5] ={ // Metadata. Elemen pertama adalah jumlah frame. { 4, 0, 0, 0, 0 }, // Kaki rata, Putar ke kiri { 150, LeftHipOut(HIP_DELTA), LeftFootFlat(), RightHipIn(HIP_DELTA), RightFootFlat() }, // Feet flat, Feet even { 150 , LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() }, // Kaki rata, Putar ke kanan { 150, LeftHipIn(HIP_DELTA), LeftFootFlat(), RightHipOut(HIP_DELTA), RightFootFlat() }, // Kaki datar, Kaki genap { 150, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() } };// Wobble anim. Miringkan ke kiri dan ke kanan untuk melakukan wobble.int wobbleAnim[][5] ={ // Metadata. Elemen pertama adalah jumlah frame. { 4, 0, 0, 0, 0 }, // Miringkan ke kiri, Kaki genap { 300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA) }, // Feet flat, Feet even { 300 , LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() }, // Miringkan ke kanan, Kaki genap { 300, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Kaki datar, Kaki genap { 300, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() } };// Goyangan kiri anim. Miringkan ke kiri dan ke belakang.int wobbleLeftAnim[][5] ={ // Metadata. Elemen pertama adalah jumlah frame. { 2, 0, 0, 0, 0 }, // Miringkan ke kiri, Kaki genap { 300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA) }, // Feet flat, Feet even { 300 , LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() },};// Goyangan animasi kanan. Miringkan ke kanan dan ke belakang.int wobbleRightAnim[][5] ={ // Metadata. Elemen pertama adalah jumlah frame. { 2, 0, 0, 0, 0 }, // Miringkan ke kanan, Kaki genap { 300, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Feet flat, Feet even { 300 , LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() } };// Ketuk kaki anim. Ketuk kedua kaki.int tapFeetAnim[][5] ={ // Metadata. Elemen pertama adalah jumlah frame. { 2, 0, 0, 0, 0 }, // Angkat kedua kaki, Kaki genap { 500, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Kaki rata, Kaki genap { 500, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() },};// Ketuk kaki kiri anim.int tapLeftFootAnim[][5] ={ // Metadata. Elemen pertama adalah jumlah frame. { 2, 0, 0, 0, 0 }, // Angkat kaki kiri, Kaki genap { 500, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootFlat() }, // Kaki rata, Kaki genap { 500 , LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() },};// Ketuk kaki kanan anim.int tapRightFootAnim[][5] ={ // Metadata. Elemen pertama adalah jumlah frame. { 2, 0, 0, 0, 0 }, // Angkat kaki kanan, Kaki genap { 500, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Kaki rata, Kaki genap { 500 , LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() },};// Memantul ke atas dan ke bawah anim.int bounceAnim[][5] ={ // Metadata. Elemen pertama adalah jumlah frame. { 2, 0, 0, 0, 0 }, // Angkat kedua kaki, Kaki genap { 500, LeftHipCentre(), LeftFootDown(300), RightHipCentre(), RightFootDown(300) }, // Kaki rata, Kaki genap { 500, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() },};// Shake Legs Animation.int shakeLegsAnim[][5] ={ // Metadata. Elemen pertama adalah jumlah frame. { 14, 0, 0, 0, 0 }, // Miringkan ke kiri, Kaki genap { 300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA) }, // Miringkan ke kiri, Pinggul kanan di { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA) }, // Miringkan ke kiri, Kaki genap { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDELTA(FOOT_DELTA) , // Miringkan ke kiri, Pinggul kanan keluar { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipOut(HIP_DELTA), RightFootDown(FOOT_DELTA) }, // Miringkan ke kiri, Kaki genap { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA) , RightHipCentre(), RightFootDown(FOOT_DELTA) }, // Miringkan ke kiri, Pinggul kanan di { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA) }, // Miringkan ke kiri, Kaki genap { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA) }, // Feet flat, Feet even { 300, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() }, // rig miring ht, Kaki genap { 300, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Pinggul kiri di { 100, LeftHipIn(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipCentre() , RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Kaki genap { 100, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Pinggul kiri keluar { 100, LeftHipOut(HIP_DELTA) ), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Kaki genap { 100, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Kaki datar , Kaki genap { 300, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() } };// Shake Left Leg Animation.int shakeLeftLegAnim[][5] ={ // Metadata. Elemen pertama adalah jumlah frame. { 12, 0, 0, 0, 0 }, // Miringkan ke kanan, Kaki genap { 300, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Pinggul kiri di { 100, LeftHipIn(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Kaki genap { 100, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) , // Miringkan ke kanan, Pinggul kiri keluar { 100, LeftHipOut(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Kaki genap { 100, LeftHipCentre(), LeftFootDown(FOOT_DELTA) , RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Pinggul kiri di { 100, LeftHipIn(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Kaki genap { 100, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Pinggul kiri keluar { 100, LeftHipOut(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFo otUp(FOOT_DELTA) }, // Miringkan ke kanan, Kaki genap { 100, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Pinggul kiri di { 100, LeftHipIn(HIP_DELTA) , LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Miringkan ke kanan, Kaki genap { 100, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Kaki datar, Kaki genap { 300, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() } };// Shake Right Leg Animation.int shakeRightLegAnim[][5] ={ // Metadata. Elemen pertama adalah jumlah frame. { 12, 0, 0, 0, 0 }, // Miringkan ke kiri, Kaki genap { 300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA) }, // Miringkan ke kiri, Pinggul kanan di { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA) }, // Miringkan ke kiri, Kaki genap { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDELTA(FOOT_DELTA) , // Miringkan ke kiri, Pinggul kanan keluar { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipOut(HIP_DELTA), RightFootDown(FOOT_DELTA) }, // Miringkan ke kiri, Kaki genap { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA) , RightHipCentre(), RightFootDown(FOOT_DELTA) }, // Miringkan ke kiri, Pinggul kanan di { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA) }, // Miringkan ke kiri, Kaki genap { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA) }, // Miringkan ke kiri, Pinggul kanan keluar { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipOut(HIP_DELTA), RightFootDown (FOOT_DELTA) }, // Miringkan ke kiri, Kaki genap { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA) }, // Miringkan ke kiri, Pinggul kanan di { 100, LeftHipCentre(), LeftFootUp (FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA) }, // Miringkan ke kiri, Kaki genap { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA) }, // Kaki rata, Kaki bahkan { 300, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() }, };//------------------------- -------------------------------------------------- -------// Data animasi dinamis khusus untuk pengaturan/tweening posisi servo.//---------------------------- -------------------------------------------------- ----// Ini adalah 2 data anim khusus yang kami gunakan untuk fungsi SetServos(). Mereka memiliki// satu bingkai. Mereka akan mengubah data dalam data anim ini dan memutarnya ke // memindahkan servos.int setServosAnim1[][5] ={ // Metadata. Elemen pertama adalah jumlah frame. { 1, 0, 0, 0, 0 }, // Tilt left, Feet even { 0, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() }};int setServosAnim2[][5] ={ // Metadata. First element is number of frames. { 1, 0, 0, 0, 0 }, // Tilt left, Feet even { 0, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() }};//----------------------------------------------------------------------------------// Servo Variables//----------------------------------------------------------------------------------Servo servoLeftHip;Servo servoLeftFoot;Servo servoRightHip;Servo servoRightFoot;//----------------------------------------------------------------------------------// State variables for playing animations.//----------------------------------------------------------------------------------// Milliseconds between animation updates.const int millisBetweenAnimUpdate =20;// Time when we did the last animation update.long timeAtLastAnimUpdate;// Related to currently playing anim.int (*currAnim)[5]; // Current animation we're playing.int (*finishAnim)[5]; // Animation to play when the currAnim finishes or is stopped.long timeAtStartOfFrame; // millis() at last keyframe - frame we're lerping fromint targetFrame; // Frame we are lerping toint animNumLoops; // Number of times to play the animation. -1 means loop forever.char animCompleteStr[3] ="--"; // This is a 2 character string. When the anim is complete, // we print out the status as "<" + animComplereStr + ">".// Related to anim queue. I.e. Next anim to play.bool animInProgress; // Whether an animation is playingint (*nextAnim)[5]; // This is the next animation to play once the current one is done. // i.e. It's like a queue of size 1! // If curr is non-looping, we play this at the end of the current anim. // If curr is looping, this starts at the end of the current loop, // replacing curr anim. // If nothing is playing, this starts right away. int (*nextFinishAnim)[5]; // This is the finish animation for the queued animation.int nextAnimNumLoops; // Number of times to play the animation. -1 means loop forever.char nextAnimCompleteStr[3] ="--"; // This is a 2 character string. When the anim is complete, // we print out the status as "<" + animComplereStr + ">".bool interruptInProgressAnim; // Whether to change anim immediately, interrupting the current one.// Curr servo positionsint currLeftHip;int currLeftFoot;int currRightHip;int currRightFoot;// Servo positions at start of current keyframeint startLeftHip;int startLeftFoot;int startRightHip;int startRightFoot;//-------------------------------------------------------------------------------// Parser Variables//-------------------------------------------------------------------------------// Constant delimiter tag charsconst char START_CHAR ='<';const char END_CHAR ='>';const char SEP_CHAR =',';// Constants and a variable for the parser state.const int PARSER_WAITING =0; // Waiting for '<' to start parsing.const int PARSER_COMMAND =1; // Reading the command string.const int PARSER_PARAM1 =2; // Reading param 1.const int PARSER_PARAM2 =3; // Reading param 2.const int PARSER_PARAM3 =4; // Reading param 3.const int PARSER_PARAM4 =5; // Reading param 3.const int PARSER_PARAM5 =6; // Reading param 3.const int PARSER_EXECUTE =7; // Finished parsing a command, so execute it.// Current parser state.int currParserState =PARSER_WAITING; // String for storing the command. 2 chars for the command and 1 char for '\0'.// We store the command here as we're parsing.char currCmd[3] ="--";// For tracking which letter we are in the command.int currCmdIndex;// Max command length.const int CMD_LENGTH =2;// Current param values. Store them here after we parse them.int currParam1Val;int currParam2Val;int currParam3Val;int currParam4Val;int currParam5Val;// Variable for tracking which digit we're parsing in a param.// We use this to convert the single digits back into a decimal value.int currParamIndex;// Whether the current param is negative.boolean currParamNegative;// Max parameter length. Stop parsing if it exceeds this.const int MAX_PARAM_LENGTH =6;//===============================================================================// Arduino setup() and loop().//===============================================================================void setup() { // Setup the main serial port softwareSerial.begin(SERIAL_SPEED); // Setup the Servos servoLeftHip.attach( SERVO_LEFT_HIP, LEFT_HIP_MIN, LEFT_HIP_MAX); servoLeftFoot.attach( SERVO_LEFT_FOOT, LEFT_FOOT_MIN, LEFT_FOOT_MAX); servoRightHip.attach( SERVO_RIGHT_HIP, RIGHT_HIP_MIN, RIGHT_HIP_MAX); servoRightFoot.attach(SERVO_RIGHT_FOOT, RIGHT_FOOT_MIN, RIGHT_FOOT_MAX); // Set things up for the parser. setup_Parser(); // Set things up for the animation code. setup_Animation();}void loop() { // Update the parser. loop_Parser(); // Update the animation. loop_Animation();}//===============================================================================// Related to the parser//===============================================================================// Sets up the parser stuff. Called in setup(). Should not be called elsewhere.void setup_Parser(){ // Wait for first command. currParserState =PARSER_WAITING; // Print this response to say we've booted and are ready. softwareSerial.println("");}// Loop() for the parser stuff. Called in loop(). Should not be called elsewhere.void loop_Parser(){ //--------------------------------------------------------- // PARSER // // If there is data, parse it and process it. //--------------------------------------------------------- // Read from pin serial port and write it out on USB port. if (softwareSerial.available()> 0) { char c =softwareSerial.read(); // If we're in WAITING state, look for the START_CHAR. if (currParserState ==PARSER_WAITING) { // If it's the START_CHAR, move out of this state... if (c ==START_CHAR) { // Start parsing the command. currParserState =PARSER_COMMAND; // Reset thing ready for parsing currCmdIndex =0; currCmd[0] ='-'; currCmd[1] ='-'; currParam1Val =0; currParam2Val =0; currParam3Val =0; currParam4Val =0; currParam5Val =0; } // Otherwise, stay in this state. } // In the state to look for the command. else if (currParserState ==PARSER_COMMAND) { // Else if it's a separator, parse parameter 1. But make sure it's not // empty, or else it's a parse error. if (c ==SEP_CHAR) { if (currCmdIndex ==CMD_LENGTH) { currParserState =PARSER_PARAM1; currParamIndex =0; currParamNegative =false; } else { currParserState =PARSER_WAITING; } } // Else if it's the end char, there are no parameters, so we're ready to // process. But make sure it's not empty. Otherwise, it's a parse error. else if (c ==END_CHAR) { if (currCmdIndex ==CMD_LENGTH) { currParserState =PARSER_EXECUTE; } else { currParserState =PARSER_WAITING; } } // If we've got too many letters here, we have a parse error, // so abandon and go back to PARSER_WAITING else if ( (currCmdIndex>=CMD_LENGTH) || (c <'A') || (c> 'Z') ) { currParserState =PARSER_WAITING; } // Store the current character. else { currCmd[currCmdIndex] =c; currCmdIndex++; } } // In the state to parse param 1. else if (currParserState ==PARSER_PARAM1) { // Else if it's a separator, parse parameter 1. if (c ==SEP_CHAR) { if (currParamNegative) { currParam1Val =-1 * currParam1Val; } currParserState =PARSER_PARAM2; currParamIndex =0; currParamNegative =false; } // Else if it's the end char, there are no parameters, so we're ready to // process. else if (c ==END_CHAR) { if (currParamNegative) { currParam1Val =-1 * currParam1Val; } currParserState =PARSER_EXECUTE; } // Check for negative at the start. else if ( (currParamIndex ==0) &&(c =='-') ) { currParamNegative =true; currParamIndex++; } // If it's too long, or the character is not a digit, then it's // a parse error, so abandon and go back to PARSER_WAITING. else if ( (currParamIndex>=MAX_PARAM_LENGTH) || (c <'0') || (c> '9') ) { currParserState =PARSER_WAITING; } // It's a valid character, so process it. else { // Shift existing value across and add new digit at the bottom. int currDigitVal =c - '0'; currParam1Val =(currParam1Val * 10) + currDigitVal; currParamIndex++; } } // In the state to parse param 2. else if (currParserState ==PARSER_PARAM2) { // Else if it's a separator, parse parameter 2. if (c ==SEP_CHAR) { if (currParamNegative) { currParam2Val =-1 * currParam2Val; } currParserState =PARSER_PARAM3; currParamIndex =0; currParamNegative =false; } // Else if it's the end char, there are no parameters, so we're ready to // process. else if (c ==END_CHAR) { if (currParamNegative) { currParam2Val =-1 * currParam2Val; } currParserState =PARSER_EXECUTE; } // Check for negative at the start. else if ( (currParamIndex ==0) &&(c =='-') ) { currParamNegative =true; currParamIndex++; } // If it's too long, or the character is not a digit, then it's // a parse error, so abandon and go back to PARSER_WAITING. else if ( (currParamIndex>=MAX_PARAM_LENGTH) || (c <'0') || (c> '9') ) { currParserState =PARSER_WAITING; } // It's a valid character, so process it. else { // Shift existing value across and add new digit at the bottom. int currDigitVal =c - '0'; currParam2Val =(currParam2Val * 10) + currDigitVal; currParamIndex++; } } // In the state to parse param 3. else if (currParserState ==PARSER_PARAM3) { // Else if it's a separator, parse parameter 2. if (c ==SEP_CHAR) { if (currParamNegative) { currParam3Val =-1 * currParam3Val; } currParserState =PARSER_PARAM4; currParamIndex =0; currParamNegative =false; } // Else if it's the end char, there are no parameters, so we're ready to // process. else if (c ==END_CHAR) { if (currParamNegative) { currParam3Val =-1 * currParam3Val; } currParserState =PARSER_EXECUTE; } // Check for negative at the start. else if ( (currParamIndex ==0) &&(c =='-') ) { currParamNegative =true; currParamIndex++; } // If it's too long, or the character is not a digit, then it's // a parse error, so abandon and go back to PARSER_WAITING. else if ( (currParamIndex>=MAX_PARAM_LENGTH) || (c <'0') || (c> '9') ) { currParserState =PARSER_WAITING; } // It's a valid character, so process it. else { // Shift existing value across and add new digit at the bottom. int currDigitVal =c - '0'; currParam3Val =(currParam3Val * 10) + currDigitVal; currParamIndex++; } } // In the state to parse param 4. else if (currParserState ==PARSER_PARAM4) { // Else if it's a separator, parse parameter 2. if (c ==SEP_CHAR) { if (currParamNegative) { currParam4Val =-1 * currParam4Val; } currParserState =PARSER_PARAM5; currParamIndex =0; currParamNegative =false; } // Else if it's the end char, there are no parameters, so we're ready to // process. else if (c ==END_CHAR) { if (currParamNegative) { currParam4Val =-1 * currParam4Val; } currParserState =PARSER_EXECUTE; } // Check for negative at the start. else if ( (currParamIndex ==0) &&(c =='-') ) { currParamNegative =true; currParamIndex++; } // If it's too long, or the character is not a digit, then it's // a parse error, so abandon and go back to PARSER_WAITING. else if ( (currParamIndex>=MAX_PARAM_LENGTH) || (c <'0') || (c> '9') ) { currParserState =PARSER_WAITING; } // It's a valid character, so process it. else { // Shift existing value across and add new digit at the bottom. int currDigitVal =c - '0'; currParam4Val =(currParam4Val * 10) + currDigitVal; currParamIndex++; } } // In the state to parse param 5. else if (currParserState ==PARSER_PARAM5) { // If it's the end char, there are no parameters, so we're ready to // process. if (c ==END_CHAR) { if (currParamNegative) { currParam5Val =-1 * currParam5Val; } currParserState =PARSER_EXECUTE; } // Check for negative at the start. else if ( (currParamIndex ==0) &&(c =='-') ) { currParamNegative =true; currParamIndex++; } // If it's too long, or the character is not a digit, then it's // a parse error, so abandon and go back to PARSER_WAITING. else if ( (currParamIndex>=MAX_PARAM_LENGTH) || (c <'0') || (c> '9') ) { currParserState =PARSER_WAITING; } // It's a valid character, so process it. else { // Shift existing value across and add new digit at the bottom. int currDigitVal =c - '0'; currParam5Val =(currParam5Val * 10) + currDigitVal; currParamIndex++; } } //--------------------------------------------------------- // PARSER CODE HANDLER (Still part of Parser, but section that // processes completed commands) // // If the most recently read char completes a command, // then process the command, and clear the state to // go back to looking for a new command. // // The parsed items are stored in:// currCmd, currParam1Val, currParam2Val, currParam3Val, // currParam4Val, currParam5Val //--------------------------------------------------------- if (currParserState ==PARSER_EXECUTE) { // Ready/OK Check: if ((currCmd[0] =='O') &&(currCmd[1] =='K')) { softwareSerial.println(""); } // Set Servo: // time - time to tween to specified angles // leftHip - microsecs from centre. -ve is hip in, +ve is hip out // leftFoot - microsecs from flat. -ve is foot down, +ve is foot up // rightHip - microsecs from centre. -ve is hip in, +ve is hip out // rightFoot - microsecs from flat. -ve is foot down, +ve is foot up else if ((currCmd[0] =='S') &&(currCmd[1] =='V')) { int tweenTime =currParam1Val; if (currParam1Val <0) { tweenTime =0; } SetServos(tweenTime, currParam2Val, currParam3Val, currParam4Val, currParam5Val, "SV"); } // Stop/Reset:, Stops current anim. Also can be used to put robot into reset position. else if ((currCmd[0] =='S') &&(currCmd[1] =='T')) { StopAnim("ST"); } // Stop Immediate: else if ((currCmd[0] =='S') &&(currCmd[1] =='I')) { StopAnimImmediate("SI"); } // Forward:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='F') &&(currCmd[1] =='W')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(walkForwardAnim, walkEndAnim, numTimes, "FW"); } // Backward:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='B') &&(currCmd[1] =='W')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(walkBackwardAnim, walkEndAnim, numTimes, "BW"); } // Turn Left:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='L') &&(currCmd[1] =='T')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(turnLeftAnim, NULL, numTimes, "LT"); } // Turn Right:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='R') &&(currCmd[1] =='T')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(turnRightAnim, NULL, numTimes, "RT"); } // Shake Head:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='S') &&(currCmd[1] =='X')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(shakeHeadAnim, NULL, numTimes, "SX"); } // Bounce:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='B') &&(currCmd[1] =='X')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(bounceAnim, NULL, numTimes, "BX"); } // Wobble:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='W') &&(currCmd[1] =='X')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(wobbleAnim, NULL, numTimes, "WX"); } // Wobble Left:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='W') &&(currCmd[1] =='Y')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(wobbleLeftAnim, NULL, numTimes, "WY"); } // Wobble Right:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='W') &&(currCmd[1] =='Z')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(wobbleRightAnim, NULL, numTimes, "WZ"); } // Tap Feet:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='T') &&(currCmd[1] =='X')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(tapFeetAnim, NULL, numTimes, "TX"); } // Tap Left Foot:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='T') &&(currCmd[1] =='Y')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(tapLeftFootAnim, NULL, numTimes, "TY"); } // Tap Right Foot:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='T') &&(currCmd[1] =='Z')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(tapRightFootAnim, NULL, numTimes, "TZ"); } // Shake Legs:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='L') &&(currCmd[1] =='X')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(shakeLegsAnim, NULL, numTimes, "LX"); } // Shake Left Leg:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='L') &&(currCmd[1] =='Y')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(shakeLeftLegAnim, NULL, numTimes, "LY"); } // Shake Right Leg:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='L') &&(currCmd[1] =='Z')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(shakeRightLegAnim, NULL, numTimes, "LZ"); } //-------------------------------------------------- // Clear the state and wait for the next command! // This must be done! //-------------------------------------------------- currParserState =PARSER_WAITING; } }}//===============================================================================// Related to playing servo animations.//===============================================================================// Call this to play the given animation once. Pass in NULL if there is no finishAnim.void PlayAnim(int animToPlay[][5], int finishAnim[][5], const char *completeStr){ // Put this in the queue. PlayAnimNumTimes(animToPlay, finishAnim, 1, completeStr);}// Call this to loop the given animation. Pass in NULL if there is no finishAnim.void LoopAnim(int animToPlay[][5], int finishAnim[][5], const char *completeStr){ // Put this in the queue. PlayAnimNumTimes(animToPlay, finishAnim, -1, completeStr);}// Call this to play the given animation the specified number of times. // -1 number of times will make it loop forever.// Pass in NULL if there is no finishAnim.void PlayAnimNumTimes(int animToPlay[][5], int finishAnim[][5], int numTimes, const char *completeStr){ // Put this in the queue. nextAnim =animToPlay; nextFinishAnim =finishAnim; nextAnimNumLoops =numTimes; // Save the completeStr if (completeStr ==NULL) { nextAnimCompleteStr[0] ='-'; nextAnimCompleteStr[1] ='-'; } else { nextAnimCompleteStr[0] =completeStr[0]; nextAnimCompleteStr[1] =completeStr[1]; }}// Stop after the current animation.void StopAnim(const char *completeStr){ // Put this in the queue. PlayAnimNumTimes(standStraightAnim, NULL, 1, completeStr);}// Stop immediately and lerp robot to zero position, interrupting // any animation that is in progress.void StopAnimImmediate(const char *completeStr){ // Put this in the queue. interruptInProgressAnim =true; PlayAnimNumTimes(standStraightAnim, NULL, 1, completeStr);}// Moves servos to the specified positions. Time 0 will make it immediate. Otherwise,// it'll tween it over a specified time.// For positions, 0 means centered.// For hips, -ve is hip left, +ve is hip right// For feet, -ve is foot down, +ve is foot upvoid SetServos(int tweenTime, int leftHip, int leftFoot, int rightHip, int rightFoot, const char* completeStr){ // Save the completeStr if (completeStr ==NULL) { nextAnimCompleteStr[0] ='-'; nextAnimCompleteStr[1] ='-'; } else { nextAnimCompleteStr[0] =completeStr[0]; nextAnimCompleteStr[1] =completeStr[1]; } // Decide which tween data we use. We don't want to over-write the one that is // in progress. We have and reuse these to keep memory allocation fixed. int (*tweenServoData)[5]; if (currAnim !=setServosAnim1) { tweenServoData =setServosAnim1; } else { tweenServoData =setServosAnim2; } // Set the tween information into the animation data. tweenServoData[1][TWEEN_TIME_VALUE] =tweenTime; tweenServoData[1][LEFT_HIP_VALUE] =LeftHipIn(leftHip); tweenServoData[1][LEFT_FOOT_VALUE] =LeftFootUp(leftFoot); tweenServoData[1][RIGHT_HIP_VALUE] =RightHipIn(rightHip); tweenServoData[1][RIGHT_FOOT_VALUE] =RightFootUp(rightFoot); // Queue this tween to be played next. PlayAnim(tweenServoData, NULL, completeStr);}// Set up variables for animation. This is called in setup(). Should be not called by anywhere else.void setup_Animation(){ // Set the servos to the feet flat, feet even position. currLeftHip =LEFT_HIP_CENTRE; currLeftFoot =LEFT_FOOT_CENTRE; currRightHip =RIGHT_HIP_CENTRE; currRightFoot =RIGHT_FOOT_CENTRE; UpdateServos(); // Set the "start" positions to the current ones. So, when // we pay the next anim, we will tween from the current positions. startLeftHip =currLeftHip; startLeftFoot =currLeftFoot; startRightHip =currRightHip; startRightFoot =currRightFoot; // No animation is playing yet, and nothing in the queue yet. timeAtLastAnimUpdate =millis(); animInProgress =false; interruptInProgressAnim =false; currAnim =NULL; finishAnim =NULL; nextAnim =NULL; nextFinishAnim =NULL;}// Loop function for processing animation. This is called in every loop(). Should be be called by anywhere else.//// NOTE:The way looping animations work is that they basically add themselves back to the queue// when a cycle is done, and if there's nothing already queued up! This way, looping animations// work in a similar way to single-play animations, and fits into the queueing system.void loop_Animation(){ // Get the time at the start of this frame. long currTime =millis(); //-------------------------------------------------------------------------------------- // Decide if we want to perform the animation update. We don't execute this every frame. //-------------------------------------------------------------------------------------- if (timeAtLastAnimUpdate + millisBetweenAnimUpdate> currTime) { // Not yet time to do an anim update, so jump out. kembali; } else { // We reset the timer, and then proceed below to handle the current anim update. timeAtLastAnimUpdate =currTime; } //-------------------------------------------------------------------------------------- // Decide if we need to setup and start a new animation. We do if there's no anim // playing or we've been asked to interrupt the anim. //-------------------------------------------------------------------------------------- if ( (nextAnim !=NULL) &&(!animInProgress || interruptInProgressAnim) ) { // If this was an interrupt, we also set the "start" servo positions // to the current ones. This way, the animation system will tween from the // current positions. if (interruptInProgressAnim) { // This is the place to notify someone of an animation finishing after getting interrupted // Print the command string we just finished. -1 parameter indicates it was interrupted. softwareSerial.print("<"); softwareSerial.print(animCompleteStr); softwareSerial.println(",-1>"); // Set the "start" positions to the current ones. So, when // we pay the next anim, we will tween from the current positions. startLeftHip =currLeftHip; startLeftFoot =currLeftFoot; startRightHip =currRightHip; startRightFoot =currRightFoot; // We've handled any interrupt request, so clear the flag. interruptInProgressAnim =false; } // Store the animation we are now playing. currAnim =nextAnim; finishAnim =nextFinishAnim; animCompleteStr[0] =nextAnimCompleteStr[0]; animCompleteStr[1] =nextAnimCompleteStr[1]; nextAnim =NULL; // Queue is cleared. nextFinishAnim =NULL; nextAnimCompleteStr[0] ='-'; nextAnimCompleteStr[1] ='-'; // Record the number of times to play the animation. animNumLoops =nextAnimNumLoops; // Treat current time as start of frame for the initial lerp to the first frame. timeAtStartOfFrame =currTime; // Set the frame counters. targetFrame =1; // First frame we are lerping to. Index 0 is metadata, so skip. // An animation is now in progress animInProgress =true; } //-------------------------------------------------------------------------------------- // If we are currently playing an animation, then update the animation state and the // servo positions. //-------------------------------------------------------------------------------------- if (animInProgress) { // Determine if we need to switch to the next frame. int timeInCurrFrame =currTime - timeAtStartOfFrame; if (timeInCurrFrame> currAnim[targetFrame][TWEEN_TIME_VALUE]) { // Set the servo positions to the targetFrame's values. // We only set this if the value is> 0. -ve values means that // the current target keyframe did not alter that servos position. if (currAnim[targetFrame][LEFT_HIP_VALUE]>=0) { currLeftHip =currAnim[targetFrame][LEFT_HIP_VALUE]; } if (currAnim[targetFrame][LEFT_FOOT_VALUE]>=0) { currLeftFoot =currAnim[targetFrame][LEFT_FOOT_VALUE]; } if (currAnim[targetFrame][RIGHT_HIP_VALUE]>=0) { currRightHip =currAnim[targetFrame][RIGHT_HIP_VALUE]; } if (currAnim[targetFrame][RIGHT_FOOT_VALUE]>=0) { currRightFoot =currAnim[targetFrame][RIGHT_FOOT_VALUE]; } UpdateServos(); // These current values are now the start of frame values. startLeftHip =currLeftHip; startLeftFoot =currLeftFoot; startRightHip =currRightHip; startRightFoot =currRightFoot; // Now, we try to move to the next frame. // - If there is a next frame, set that as the new target, and proceed. // - If there's no next frame, but it's looping, we re-add this animation // to the queue. // - If there's no next frame, and this is not looping, we stop animating. // (Remember that targetFrame is 1-based since the first element of the animation // data array is metadata) // Increment targetFrame, and reset time in the current frame. targetFrame++; timeAtStartOfFrame =currTime; // If there is no next frame, we stop this current animation. // If it is looping, then we re-queue the current animation if the queue is empty. if (targetFrame> NumOfFrames(currAnim)) { // Stop the current animation. animInProgress =false; // If we're looping forever, and there's no next anim, re-queue the // animation if the queue is empty. if ((animNumLoops <0) &&(nextAnim ==NULL)) { LoopAnim(currAnim, finishAnim, animCompleteStr); } // If we're looping forever, and there is something in the queue, then // finish the animation and proceed. else if ((animNumLoops <0) &&(nextAnim !=NULL)) { if (finishAnim !=NULL) { // Switch to the finish anim. currAnim =finishAnim; finishAnim =NULL; // Record the number of times to play the animation. animNumLoops =1; // Treat current time as start of frame for the initial lerp to the first frame. timeAtStartOfFrame =currTime; // Set the frame counters. targetFrame =1; // First frame we are lerping to. Index 0 is metadata, so skip. // An animation is now in progress animInProgress =true; } else { // We've stopped, so can notify if needed. // Print the command string we just finished. softwareSerial.print("<"); softwareSerial.print(animCompleteStr); softwareSerial.println(">"); } } // If we're looping a limited number of times, and there's no next anim, // re-queue the animation if the queue is empty. else if ((animNumLoops> 1) &&(nextAnim ==NULL)) { PlayAnimNumTimes(currAnim, finishAnim, animNumLoops-1, animCompleteStr); } // In this case, numAnimLoops is 1, this is the last loop through, so // we're done. We play the finishAnim first if needed. else { // If there is a finish animation, switch to that animation. if (finishAnim !=NULL) { // Switch to the finish anim. currAnim =finishAnim; finishAnim =NULL; // Record the number of times to play the animation. animNumLoops =1; // Treat current time as start of frame for the initial lerp to the first frame. timeAtStartOfFrame =currTime; // Set the frame counters. targetFrame =1; // First frame we are lerping to. Index 0 is metadata, so skip. // An animation is now in progress animInProgress =true; } // Otherwise, we're done! We've played the finishAnim if there was one. else { // Print the command string we just finished. softwareSerial.print("<"); softwareSerial.print(animCompleteStr); softwareSerial.println(">"); } } } } // If we're still animating (i.e. the previous check didn't find that // we've finished the current animation), then proceed. if (animInProgress) { // Set the servos per data in the current frame. We only update the servos that have target // microsecond values> 0. This is to support the feature where we leave a servo at its // existing position if an animation data item is -1. float frameTimeFraction =(currTime - timeAtStartOfFrame) / ((float) currAnim[targetFrame][TWEEN_TIME_VALUE]); if (currAnim[targetFrame][LEFT_HIP_VALUE]>=0) { currLeftHip =startLeftHip + ((currAnim[targetFrame][LEFT_HIP_VALUE] - startLeftHip) * frameTimeFraction); } if (currAnim[targetFrame][LEFT_FOOT_VALUE]>=0) { currLeftFoot =startLeftFoot + ((currAnim[targetFrame][LEFT_FOOT_VALUE] - startLeftFoot) * frameTimeFraction); } if (currAnim[targetFrame][RIGHT_HIP_VALUE]>=0) { currRightHip =startRightHip + ((currAnim[targetFrame][RIGHT_HIP_VALUE] - startRightHip) * frameTimeFraction); } if (currAnim[targetFrame][RIGHT_FOOT_VALUE]>=0) { currRightFoot =startRightFoot + ((currAnim[targetFrame][RIGHT_FOOT_VALUE] - startRightFoot) * frameTimeFraction); } UpdateServos(); } }}// Move all the servo to the positions set in the curr... variables.// In the code, we update those variables and then call this to set the servos.void UpdateServos(){ servoLeftHip.writeMicroseconds(currLeftHip); servoLeftFoot.writeMicroseconds(currLeftFoot); servoRightHip.writeMicroseconds(currRightHip); servoRightFoot.writeMicroseconds(currRightFoot);}// Return the number of frames in the given animation data.// Have this helper function to avoid the "magic number" reference of animData[0][0].int NumOfFrames(int animData[][5]){ return animData[0][0];}

Skema


Proses manufaktur

  1. Robot Raspberry Pi dikendalikan melalui Bluetooth
  2. DIY LUMAZOID Arduino Music Visualizer
  3. Arduino Digital Dice
  4. Game Roulette LED 37 DIY
  5. Voltmeter DIY Menggunakan Arduino dan Smartphone
  6. Robot yang Dikendalikan Bicara
  7. Robot Piano Terkendali Arduino:PiBot
  8. NeoMatrix Arduino Pong
  9. Lengan Robot Arduino DIY – Dikendalikan oleh Gerakan Tangan
  10. Robot 4-Roda Dibuat Dengan Arduino Dikontrol Menggunakan Dabble