
Kami terus membongkar komponen perangkat lunak platform MIRO. Saya ingin memeriksa lebih detail tepatnya peranti lunak di bawah AVR. Karena itu, kami akan mencurahkan dua bagian untuk masalah ini. Dalam yang pertama, kami menggambarkan struktur umum perpustakaan, dan yang kedua, implementasi beberapa metode kelas utama.
Daftar Isi:
Bagian 1 ,
Bagian 2 ,
Bagian 3 ,
Bagian 4 ,
Bagian 5 .
Perangkat lunak di bawah ARDUINO ternyata menjadi yang terbesar dari yang ditulis sendiri. Secara umum, hampir semua logika langsung bekerja dengan aktuator dan sensor robot terletak pada AVR. Dan pada level ini, API diimplementasikan - pustaka perangkat lunak pengembangan cepat untuk MIRO.
Struktur API dijelaskan di bagian wiki dari
repositori yang sesuai. Sejauh ini, hanya dalam bahasa Rusia. Dan sekarang kita akan menganalisis kode lebih terinci. Saya sengaja tidak akan memberikan deklarasi kelas yang lengkap, menguranginya dengan elipsis "...", hanya menyisakan hal-hal yang signifikan saat ini.
Dalam model perangkat lunak kami, setiap robot MIRO terdiri dari sasis dan satu set perangkat yang terhubung. Saat mendesain, diasumsikan bahwa sasis robot - akan selalu menjadi semacam sasis beroda - robot berjalan atau robot yang menggunakan beberapa prinsip gerakan lain harus dipertimbangkan secara terpisah.
class Miro : public Robot { public: Miro(byte *PWM_pins, byte *DIR_pins); #if defined(ENCODERS_ON) Miro(byte *PWM_pins, byte *DIR_pins, byte *ENCODER_pins); #endif ~Miro(); ... };
Kelas Miro adalah kelas tingkat atas dan menjelaskan konfigurasi lengkap robot. Kelas ini adalah turunan dari kelas Robot, yang hanya menjelaskan fungsi paling dasar dari robot.
class Robot { public: Robot(byte *PWM_pins, byte *DIR_pins); #if defined(ENCODERS_ON) Robot(byte *PWM_pins, byte *DIR_pins, byte *ENCODER_pins); #endif ~Robot(); Chassis chassis; void Sync(); int attachDevice(Device *dev); int dettachDevice(Device *dev); ... protected: Device* _devices[ROBOT_MAX_DEVICES]; byte _device_count; };
Perancang melakukan pengaturan awal pin sasis dan nilai awal konfigurasi robot.
Metode Sync () mengimplementasikan operasi yang diperlukan untuk sasis dan untuk semua perangkat yang terhubung ke robot, setiap langkah siklus utama () dari sketsa ARDUINO. Metode Miro Sync () dari kelas Miro menggunakan metode Sync () pada sasis dan semua perangkat yang terhubung ke robot.
Kelas Robot juga berisi pointer ke array perangkat yang terhubung ke robot, metode untuk bekerja dengan array ini (menghubungkan perangkat baru, putuskan sambungan, temukan dengan indeks dan nama). Kelas Robot juga berisi objek dari kelas Chassis - sasis.
Tapi mari kita mulai dengan sesuatu yang lebih sederhana - dengan perangkat. Setiap perangkat yang dapat dihubungkan ke robot, baik itu LED, sensor, atau aktuator yang tidak berhubungan langsung dengan sasis (troli), dijelaskan oleh kelas penggantinya, yang umum untuk semua perangkat di kelas Perangkat virtual:
class Device { public: virtual void Sync(); virtual void setParam(byte pnum, byte *pvalue); virtual void getParam(byte pnum, byte *pvalue); virtual byte getPinsCount(); virtual char* getName(); virtual byte getParamCount(); protected: byte *pins[2]; };
Metode virtual setParam, getParam, getParamCount dikaitkan dengan menetapkan, menerima, dan menentukan jumlah parameter perangkat. Parameter dapat berupa properti apa saja: kecerahan LED, posisi drive servo, dll. Kelas penerus setiap perangkat menerapkan metode ini dengan caranya sendiri. Tujuan dari getName, metode getPinsCount, saya pikir, jelas dari namanya. Metode Sync yang baru ditemukan adalah metode khusus untuk kontrol perangkat non-pemblokiran dan otomatisasi beberapa operasi perangkat yang harus dilakukan secara teratur, setiap iterasi pada loop utama.
Mari sekarang kita lihat beberapa implementasi umum dari kelas turunan.
class MIROUsonic : virtual public Device { public: void Sync(); void setParam(byte bnum, byte *pvalue); void getParam(byte bnum, byte *pvalue); byte getPinsCount(); char* getName(); byte getParamCount(); void Init(byte trig_pin, byte echo_pin); void On(unsigned int max_dist); void On(); void Off(); int getDist(unsigned int max_dist); unsigned int getMesCount(); private: bool _isOn; unsigned int _mesCount; unsigned int _dist; unsigned int _max_dist; };
Dalam menentukan kelas pengintai ultrasonik (di atas), selain metode induk, ada juga metode:
- Init - inisialisasi;
- Nyala dan Mati - nyalakan perangkat (pengintai);
- getDist - mengembalikan jarak yang diukur oleh pencari jarak;
- getMesCount - mengembalikan jumlah pengukuran yang dilakukan sejak perangkat dihidupkan.
Untuk menyimpan keadaan internal perangkat, bidang-bidang berikut digunakan:
- _isOn (BENAR - perangkat dihidupkan, dikendalikan oleh metode Nyala dan Mati);
- _mesCount (menyimpan jumlah dimensi yang digunakan dalam metode getMesCount);
- _max_dist - jarak maksimum yang diperlukan untuk pengukuran *;
- _dist adalah jarak pengukuran aktual.
Tentang rentang pengukuran maksimum* Diketahui bahwa HC-SR04 yang tersebar luas menurut paspor mampu mengukur jarak hingga 4 meter. Namun, metode pengukuran itu sendiri melibatkan menunggu kembalinya sinyal ultrasonik, diikuti dengan pengkodean durasi dalam sinyal pada garis Echo. Dan pada kenyataannya, jika pengguna jelas tidak perlu mengukur jarak dalam kisaran hingga 4 meter, tetapi cukup, kisaran, katakanlah 1 meter, maka Anda bisa menunggu 4 kali lebih sedikit untuk sinyal yang dipantulkan. Rangefinder itu sendiri menghasilkan sinyal pada garis Echo segera setelah menerimanya dan melakukan modulasi. Yaitu ini mungkin tidak mempengaruhi panjang periode antara pengukuran yang berdekatan, tetapi durasi pengukuran tunggal dengan cara ini dapat dikurangi.
Dan sekarang untuk penjelasan tentang metode Sync. Jika perangkat memiliki status _isOn == BENAR (aktif), maka siklus pengukuran itu sendiri akan dilakukan dalam metode Sinkronisasi, dan hasil pengukuran akan dicatat dalam bidang _dist. Dalam hal ini, ketika Anda memanggil getDist, metode ini akan segera mengembalikan nilai yang direkam dalam _dist, tidak akan ada siklus pengukuran. Jika _isOn == FALSE (off), siklus pengukuran, sebaliknya, dilakukan hanya selama panggilan ke getDist, tidak ada yang akan diukur dalam metode Sync. Diasumsikan bahwa pemrogram akan memanggil metode Sinkronisasi dari seluruh robot, yang pada gilirannya akan memanggil metode Sinkronisasi dengan nama yang sama dari semua perangkat yang terhubung ke robot dan objek dari kelas Chasis (sasis).
Dari perangkat di API, hanya hal-hal yang dimiliki MIRO sekarang yang diterapkan: LED, pencari jarak ultrasonik, sensor cahaya resistif-foto, drive servo, sensor garis.
Sentuh Chassis dengan ringan. Kelas ini mengimplementasikan "kereta abstrak" dari robot. Ini berisi metode yang memungkinkan Anda untuk mengontrol pemindah.
class Chassis { public: Chassis(byte *PWM_pins, byte *DIR_pins); #if defined(ENCODERS_ON) Chassis(byte *PWM_pins, byte *DIR_pins, byte *ENCODER_pins); #endif ~Chassis(); void Sync(); float getVoltage(); int wheelRotatePWMTime(int *speedPWM, unsigned long time); int wheelRotatePWM(int *speedPWM); bool wheelIsMoving(byte wheel) {return this->_wheel_move[wheel];} byte getWheelCount() { return WHEEL_COUNT; } #if defined(ENCODERS_ON) int wheelRotateAng(float *speed, float *ang, bool en_break); unsigned long wheelGetEncoder(byte wheel); ... #endif
Jika kami mempertimbangkan keranjang tanpa penyandi dan umumnya tanpa umpan balik, maka ada metode kontrol sederhana untuk ini menggunakan sinyal PWM. Jika ada encoder di troli, kelas menjadi jauh lebih rumit. Untuk menyederhanakan kehidupan pengguna, metode seperti yang muncul di dalamnya:
- wheelRotateAng - rotasi roda pada sudut rotasi yang ditentukan sebelumnya dengan kecepatan sudut yang diberikan;
- wheelGetPath - mengembalikan panjang jalur yang dilalui oleh setiap roda;
- wheelGetLinSpeed ββ- mengembalikan kecepatan linier saat ini dari setiap roda;
- wheelGetAngSpeed ββ- mengembalikan kecepatan sudut saat ini dari setiap roda;
- wheelGetEncoder - mengembalikan jumlah respons pembuat enkode setiap roda.
Dan sejumlah metode tambahan. Serta metode kalibrasi propulsi. Tetapi secara lebih rinci metode kunci dari kelas Chassis akan dipertimbangkan kali berikutnya.
Melihat sedikit ke depan, di tempat inilah yang akan tepat untuk dicatat bahwa seluruh perpustakaan Miro ini dapat dengan mudah diadaptasi atau ditambah dengan robot lain dengan skema gerak diferensial roda dua. Dan dengan upaya tertentu - dan untuk penggerak lain dan konfigurasi kemudi. Dalam kasus rangkaian diferensial, Anda hanya perlu menjelaskan dengan benar file konfigurasi config.h. Dan tanpa RPi. Sebagai contoh, dalam waktu kurang dari satu jam, kami meluncurkan semuanya pada yang kecil untuk turnamen cybersecurity BlackMirrorCTF-2019 regional kami di universitas kami (
tautan ).

Robot memiliki antarmuka untuk akses melalui TELNET dan sistem perintah untuk remote control. Dokumen dengan sistem perintah di suatu tempat tersembunyi atau disandikan. Peserta memindai alamat IP dan membuka port pada robot itu sendiri. Dengan koneksi yang sukses, robot mengeluarkan undangan, dan para peserta mengerti bahwa mereka telah "masuk." Nah, kemudian tim membawa robot di sepanjang jalan raya ke garis finish. Awalnya, mereka ingin membuat seluruh trek dengan robot di suatu tempat di ruang terisolasi dengan kamera IP diinstal, tetapi penyelenggara memiliki beberapa masalah dengan kamera IP dan kehilangan beberapa pesona.
Itu saja untuk saat ini. Ada kemungkinan bahwa dalam perjalanan pengembangan, model program akan mengalami perubahan. By the way, baru-baru ini sedikit dimodifikasi, setelah kode tampak sedikit lebih berpengalaman OOP-shchik.
Menjelang bagian kelima - mari kita bicara tentang penyandi, sudut dan kalibrasi.