Bagaimana saya membuat sistem pelacakan optik





Itu kembali pada tahun 2015. Kacamata realitas virtual Oculus DK2 baru saja muncul untuk dijual, pasar game VR dengan cepat mendapatkan popularitas.



Peluang pemain dalam permainan semacam itu terbatas. Hanya 6 derajat kebebasan gerakan kepala yang dipantau - rotasi (dengan inersia dalam kacamata) dan gerakan dalam volume kecil di bidang pandang kamera inframerah yang dipasang pada monitor. Proses permainan terdiri dari duduk di kursi dengan gamepad di tangan, memutar kepala ke berbagai arah dan melawan rasa mual.



Kedengarannya tidak terlalu keren, tapi saya melihat ini sebagai kesempatan untuk melakukan sesuatu yang menarik, menggunakan pengalaman saya dalam pengembangan elektronik dan rasa haus akan proyek baru. Bagaimana sistem ini dapat ditingkatkan?



Tentu saja, singkirkan gamepad, kabel, berikan pemain kesempatan untuk bergerak bebas di luar angkasa, melihat tangan dan kaki mereka, berinteraksi dengan lingkungan, pemain lain, dan objek interaktif nyata.



Saya melihatnya seperti ini:



  1. Kami membawa beberapa pemain, memakai kacamata VR, laptop dan sensor di lengan, kaki dan dada mereka.
  2. Kami mengambil ruangan yang terdiri dari beberapa ruangan, koridor, pintu, melengkapinya dengan sistem pelacakan, menggantung sensor dan kunci magnet di pintu, menambahkan beberapa objek interaktif dan membuat permainan di mana geometri lokasi virtual persis mengulangi geometri ruangan nyata.
  3. Kami membuat game. Gim ini adalah misi multipemain di mana beberapa pemain memakai peralatan dan menemukan diri mereka di dunia virtual. Di dalamnya, mereka melihat diri mereka sendiri, melihat satu sama lain, dapat berjalan-jalan di sekitar lokasi, membuka pintu dan bersama-sama memecahkan masalah permainan.


Saya menceritakan ide ini kepada teman saya, yang secara tidak terduga menerimanya dengan sangat antusias dan menawarkan untuk mengambil alih masalah organisasi. Jadi kami memutuskan untuk mengacaukan startup.



Untuk mengimplementasikan fungsionalitas yang dideklarasikan, perlu untuk membuat dua teknologi utama:



  1. sebuah suit yang terdiri dari sensor pada lengan, kaki dan dada yang melacak posisi bagian tubuh pemain
  2. sistem pelacakan yang melacak pemain dan objek interaktif dalam ruang 3D.


Perkembangan teknologi kedua akan dibahas dalam artikel ini. Mungkin nanti saya akan menulis tentang yang pertama.



Sistem pelacakan.



Tentunya kami tidak memiliki anggaran untuk semua ini, jadi kami harus membuat semuanya dari bahan bekas. Untuk tugas melacak pemain di luar angkasa, saya memutuskan untuk menggunakan kamera optik dan penanda LED yang dipasang pada kacamata VR. Saya tidak memiliki pengalaman pengembangan seperti itu, tetapi saya telah mendengar sesuatu tentang OpenCV, Python, dan berpikir bahwa saya dapat melakukannya.



Sesuai rencana, jika sistem mengetahui di mana letak kamera dan bagaimana arahnya, maka dengan posisi gambar penanda pada bingkai, Anda dapat menentukan garis lurus dalam ruang 3D tempat penanda ini berada. Perpotongan dari dua garis tersebut memberikan posisi penanda akhir.







Karenanya, kamera harus dipasang di langit-langit sehingga setiap titik dalam ruang dapat dilihat oleh setidaknya dua kamera (sebaiknya lebih, untuk menghindari halangan oleh tubuh para pemain). Untuk menutupi tempat yang seharusnya dengan luas sekitar 100 meter persegi dengan pelacakan, dibutuhkan sekitar 60 kamera. Saya memilih webcam usb murah pertama yang tersedia pada saat itu.







Webcam ini harus terhubung ke sesuatu. Eksperimen telah menunjukkan bahwa saat menggunakan kabel ekstensi usb (setidaknya yang murah), kamera mulai bermasalah. Oleh karena itu, saya memutuskan untuk membagi webcam menjadi kelompok-kelompok 8 bagian dan menempelkannya ke unit sistem yang dipasang di langit-langit. Hanya ada 10 port usb di komputer rumah saya, jadi inilah saatnya untuk mulai mengembangkan bangku tes.



Arsitektur yang saya buat adalah sebagai berikut:

Bola buram akrilik dari karangan bunga dengan LED RGB yang direkatkan di dalamnya digantung di setiap kaca. Beberapa pemain seharusnya berada dalam game pada saat yang sama, jadi untuk identifikasi saya memutuskan untuk memisahkan mereka berdasarkan warna - R, G, B, RG, RB, GB, RB. Beginilah kelihatannya:







Tugas pertama yang perlu dilakukan adalah menulis program untuk menemukan bola di bingkai.



Menemukan bola di bingkai



Saya harus mencari koordinat pusat bola dan warnanya untuk identifikasi di setiap frame yang berasal dari kamera. Kedengarannya mudah. Saya mengunduh OpenCV untuk Python, colokkan kamera ke usb, tulis skrip. Untuk meminimalkan pengaruh objek yang tidak perlu dalam bingkai, saya menetapkan pencahayaan dan kecepatan rana pada kamera ke sangat minimum, dan kecerahan LED tinggi untuk mendapatkan titik terang pada latar belakang yang gelap. Pada versi pertama, algoritmanya adalah sebagai berikut:



  1. ( , , – ).
  2. .
  3. ( )






Sepertinya berfungsi, tetapi ada nuansa.



Pertama, pada kamera murah, matriksnya cukup berisik, yang menyebabkan fluktuasi konstan dari kontur cluster biner dan, karenanya, menyentak pusat. Tidak mungkin bagi pemain untuk menggerakkan gambar dalam kacamata VR, jadi masalah ini harus diselesaikan. Upaya untuk menerapkan jenis lain dari binarisasi adaptif dengan parameter yang berbeda tidak memberikan banyak pengaruh.



Kedua, resolusi kamera hanya 640 * 480, jadi pada jarak tertentu (tidak terlalu besar) bola terlihat sebagai beberapa piksel dalam bingkai dan algoritma pencarian tepi berhenti bekerja secara normal.



Saya harus menemukan algoritme baru. Ide berikut muncul di benak saya:



  1. Ubah gambar menjadi skala abu-abu
  2. Gaussian blur – ,
  3. ,


Ini bekerja jauh lebih baik, koordinat pusat tidak bergerak saat bola tidak bergerak, dan bekerja bahkan pada jarak yang sangat jauh dari kamera.



Untuk memastikan bahwa semua ini akan bekerja dengan 8 kamera di satu komputer, Anda perlu melakukan uji stres.



Uji beban Saya



menghubungkan 8 kamera ke desktop saya, mengaturnya sehingga masing-masing melihat titik bercahaya dan menjalankan skrip di mana algoritma yang dijelaskan bekerja dalam 8 proses independen (berkat pustaka multiprosesing Python) dan memproses semua utas sekaligus.



Dan ... Saya segera menemukan kegagalan. Gambar kamera muncul dan menghilang, framerate melompat dari 0 ke 100, mimpi buruk. Penyelidikan menunjukkan bahwa beberapa port usb di komputer saya terhubung ke bus yang sama melalui hub internal, itulah sebabnya kecepatan bus dibagi antara beberapa port dan tidak lagi cukup untuk bitrate kamera. Memasukkan kamera ke port yang berbeda di komputer dalam kombinasi yang berbeda menunjukkan bahwa saya hanya memiliki 4 bus usb independen. Saya harus menemukan motherboard dengan 8 bus, yang merupakan pencarian yang agak sulit.



Spoiler
Intel B85, 10 usb . 10- , OpenCV, .. 8 (?)



Saya melanjutkan uji beban. Kali ini, semua kamera terhubung dan menghasilkan aliran normal, tetapi saya segera menemukan masalah berikutnya - fps rendah. Prosesor ini 100% dimuat dan hanya berhasil memproses 8-10 frame per detik dari masing-masing dari delapan webcam.







Sepertinya kode tersebut perlu dioptimalkan. Hambatan tersebut ternyata adalah Gaussian blur (tidak mengherankan, karena Anda perlu berbelit-belit dengan matriks 9 * 9 untuk setiap piksel bingkai). Mengurangi inti tidak menyelamatkan situasi. Saya harus mencari metode lain untuk menemukan pusat titik pada bingkai.



Solusinya tiba-tiba ditemukan di fungsi SimpleBlobDetector yang terpasang di OpenCV. Dia melakukan apa yang saya butuhkan dan dengan sangat cepat. Keuntungannya dicapai karena binarisasi sekuensial gambar dengan ambang batas yang berbeda dan pencarian kontur. Hasilnya maksimal 30 fps dengan beban CPU kurang dari 40%. Uji beban berhasil!



Klasifikasi warna



Tugas selanjutnya adalah mengklasifikasikan marker berdasarkan warnanya. Nilai warna rata-rata di atas titik piksel memberikan komponen RGB yang sangat tidak stabil dan sangat bervariasi tergantung pada jarak ke kamera dan kecerahan LED. Tetapi ada solusi bagus: terjemahan dari ruang RGB dengan HSV (hue, saturation, value). Dalam representasi ini, piksel bukannya "merah", "biru", "hijau" diuraikan menjadi komponen "hue", "saturasi", "kecerahan". Dalam hal ini, saturasi dan kecerahan dapat dengan mudah dikecualikan dan diklasifikasikan hanya berdasarkan rona.







Detail teknis
, «» . , . , . «» .



:



  1. (, R – )
  2. , , . «hue – saturation»
  3. . , .
  4. , , . . , , . .. , . , - , , .






Jadi, saat ini saya telah belajar bagaimana menemukan dan mengidentifikasi penanda dalam bingkai dari sejumlah besar kamera. Sekarang Anda bisa pergi ke tahap berikutnya - melacak di luar angkasa.



Pelacakan



Saya menggunakan model kamera lubang jarum di mana semua sinar jatuh pada matriks melalui titik yang terletak pada panjang fokus matriks.







Model ini akan mengubah koordinat dua dimensi dari sebuah titik pada bingkai menjadi persamaan tiga dimensi dari sebuah garis lurus dalam ruang.



Untuk melacak koordinat 3D penanda, Anda perlu mendapatkan setidaknya dua garis berpotongan di ruang angkasa dari kamera yang berbeda dan menemukan titik perpotongannya. Tidak sulit untuk melihat marker dengan dua kamera, tetapi untuk membuat garis-garis ini, Anda memerlukan sistem untuk mengetahui segalanya tentang kamera yang terhubung: di mana mereka menggantung, pada sudut berapa, panjang fokus setiap lensa. Masalahnya adalah semua ini tidak diketahui. Perhitungan parameter membutuhkan semacam prosedur kalibrasi.



Kalibrasi Pelacakan



Pada versi pertama saya memutuskan untuk membuat kalibrasi pelacakan sesederhana mungkin.



  1. Saya menggantung blok pertama dari delapan kamera di langit-langit, menghubungkannya ke unit sistem yang tergantung di tempat yang sama, mengarahkan kamera sehingga menutupi volume permainan maksimum.
  2. Dengan menggunakan level laser dan pengintai, saya mengukur koordinat XYZ dari semua kamera dalam satu sistem koordinat
  3. Untuk menghitung orientasi dan panjang fokus kamera, saya mengukur koordinat stiker khusus. Saya menutup stiker sebagai berikut:

    • Dalam antarmuka untuk menampilkan gambar dari kamera, saya menggambar dua titik. Satu di tengah bingkai, 200 piksel lainnya di kanan tengah

    • Jika Anda melihat bingkainya, titik-titik ini jatuh di suatu tempat di dinding, lantai atau benda lain di dalam ruangan. Saya menggantung stiker kertas di tempat yang sesuai dan menggambar titik-titik di atasnya dengan spidol
    • Saya mengukur koordinat XYZ dari titik-titik ini menggunakan level dan pengintai yang sama. Secara total, untuk satu blok yang terdiri dari delapan kamera, Anda perlu mengukur koordinat kamera itu sendiri dan dua titik lagi untuk masing-masing kamera. Itu. 24 kembar tiga koordinat. Dan seharusnya ada sekitar sepuluh blok seperti itu. Ternyata pekerjaan yang panjang dan membosankan. Tapi tidak ada, saya akan membuat kalibrasi otomatis nanti.
    • Saya memulai proses perhitungan berdasarkan data yang diukur




Ada dua sistem koordinat: satu global, terkait dengan ruangan, dan sistem lokal lainnya untuk setiap kamera. Dalam algoritme saya, hasil untuk setiap kamera harus berupa matriks 4 * 4, yang berisi lokasi dan orientasinya, memungkinkan Anda mengonversi koordinat dari lokal ke global.







Idenya adalah sebagai berikut:



  1. Kami mengambil matriks asli dengan rotasi nol dan offset.
  2. , .
  3. , .
  4. , . , . . 200 . , .
  5. (, 200 ).


Tentunya masalah ini dapat diselesaikan secara analitis, tetapi untuk kesederhanaan saya menggunakan solusi numerik pada penurunan gradien. Itu tidak menakutkan, karena perhitungan akan dilakukan setelah kamera dipasang.



Untuk memvisualisasikan hasil kalibrasi, saya membuat antarmuka 2D dengan peta, di mana skrip menggambar label kamera dan arah di mana mereka melihat penanda. Segitiga mewakili orientasi kamera dan sudut pandang.







Menguji pelacakan



Anda dapat mulai menjalankan visualisasi, yang akan menunjukkan apakah orientasi kamera telah diidentifikasi dengan benar dan apakah bingkai diinterpretasikan dengan benar. Idealnya, garis yang berasal dari ikon kamera harus berpotongan pada satu titik.



Inilah yang terjadi:





Sepertinya sebenarnya, tetapi keakuratannya jelas bisa lebih tinggi. Alasan pertama ketidaksempurnaan yang muncul dalam pikiran adalah distorsi pada lensa kamera. Ini berarti bahwa distorsi ini perlu dikompensasikan.



Kalibrasi Kamera Kamera

ideal hanya memiliki satu parameter penting bagi saya - panjang fokus. Kurva kamera yang sebenarnya juga perlu memperhitungkan distorsi lensa dan offset dari pusat matriks.

Untuk mengukur parameter ini, ada prosedur kalibrasi standar, di mana serangkaian foto papan catur diambil dengan kamera terukur, di mana sudut antara bujur sangkar dikenali dengan presisi subpiksel.







Hasil kalibrasi adalah matriks yang berisi panjang fokus sepanjang dua sumbu dan offset matriks relatif terhadap pusat optik. Semua ini diukur dalam piksel.







Serta vektor koefisien distorsi







yang memungkinkan Anda mengimbangi distorsi lensa menggunakan transformasi koordinat piksel.



Dengan menerapkan transformasi dengan koefisien ini ke koordinat penanda pada bingkai, Anda dapat membawa sistem ke model kamera lubang jarum yang ideal.



Menjalankan tes pelacakan baru:







Jauh lebih baik! Terlihat sangat bagus bahkan sepertinya berfungsi.



Namun proses kalibrasi ternyata sangat suram: langsung mengukur koordinat masing-masing kamera, mulai menampilkan gambar dari masing-masing kamera, menutup stiker, mengukur koordinat tiap stiker, menuliskan hasilnya ke dalam tabel, mengkalibrasi lensa. Semua ini memakan waktu beberapa hari dan satu kilogram saraf. Saya memutuskan untuk berurusan dengan pelacakan dan menulis sesuatu yang lebih otomatis.



Menghitung koordinat penanda



Jadi, saya mendapat banyak garis lurus, tersebar di angkasa, di persimpangan yang seharusnya ada penanda. Hanya garis lurus dalam ruang yang tidak benar-benar berpotongan, tetapi berpotongan, yaitu. lulus agak jauh dari satu sama lain. Tugas saya adalah menemukan titik sedekat mungkin dengan kedua garis lurus. Secara formal, Anda perlu mencari titik tengah ruas yang tegak lurus dengan kedua garis.







Panjang segmen AB juga berguna, karena itu mencerminkan "kualitas" dari hasil yang diperoleh. Semakin pendek, semakin dekat garis lurus satu sama lain, semakin baik hasilnya.



Kemudian saya menulis algoritme pelacakan yang menghitung perpotongan garis berpasangan (dalam warna yang sama, dari kamera yang berada pada jarak yang cukup satu sama lain), mencari yang terbaik dan menggunakannya sebagai koordinat penanda. Pada frame berikutnya, mencoba menggunakan sepasang kamera yang sama untuk menghindari lompatan koordinat saat beralih ke pelacakan dengan kamera lain.



Secara paralel, saat mengembangkan setelan dengan sensor, saya menemukan fenomena aneh. Semua sensor menunjukkan nilai sudut yaw yang berbeda (arah pada bidang horizontal), seolah-olah masing-masing memiliki arah utaranya sendiri. Pertama-tama, sangat berguna untuk memeriksa apakah saya salah dalam algoritme pemfilteran data atau dalam tata letak papan, tetapi saya tidak menemukan apa pun. Kemudian saya memutuskan untuk melihat data mentah dari magnetometer dan melihat masalahnya.

Medan magnet di kamar kami diarahkan secara vertikal ke bawah! Ternyata, hal ini disebabkan besi pada struktur bangunan.



Namun kacamata VR juga menggunakan magnetometer. Mengapa mereka tidak memiliki efek ini? Saya akan memeriksanya. Ternyata dia juga memiliki kacamata ... Jika kamu duduk diam, kamu bisa melihat bagaimana dunia maya perlahan tapi pasti berputar di sekitarmu ke arah yang acak. Dalam 10 menit, dia pergi hampir 180 derajat. Dalam permainan kami, ini pasti akan menyebabkan ketidaksesuaian antara realitas virtual dan nyata dan kacamata pecah di dinding.



Tampaknya selain koordinat kacamata, Anda harus menentukan arahnya pada bidang horizontal. Solusinya menyarankan dirinya sendiri - untuk meletakkan bukan hanya satu, tetapi dua penanda identik pada kacamata. Ini akan memungkinkan Anda untuk menentukan arah dengan akurasi belokan 180 derajat, tetapi dengan mempertimbangkan keberadaan sensor inersia bawaan, ini sudah cukup.







Sistem secara keseluruhan berhasil, meskipun dengan tiang penyangga kecil. Tetapi keputusan dibuat untuk meluncurkan misi, yang baru saja akan diselesaikan oleh pengembang gamedev kami yang bergabung dengan tim mini kami. Seluruh area bermain dihancurkan, pintu dengan sensor dan kunci magnet dipasang, dan dua objek interaktif dibuat:







Pemain memakai kacamata, jas dan ransel komputer dan memasuki area bermain. Koordinat pelacakan dikirim kepada mereka melalui wi-fi dan digunakan untuk memposisikan karakter virtual. Semuanya berjalan cukup baik, para pengunjung senang. Hal yang paling menyenangkan adalah menyaksikan kengerian dan jeritan pengunjung yang sangat terkesan pada saat-saat hantu virtual menyerang mereka dari kegelapan =)







Penskalaan



Tiba-tiba, kami menerima pesanan penembak VR besar untuk 8 pemain dengan senjata di tangan mereka. Dan ini 16 objek yang perlu diguncang. Beruntung skenario mengasumsikan kemungkinan membagi pelacakan menjadi dua zona masing-masing 4 pemain, jadi saya memutuskan bahwa tidak akan ada masalah, Anda dapat mengambil pesanan dan tidak khawatir tentang apa pun. Tidak mungkin menguji sistem di rumah. membutuhkan area yang luas dan banyak peralatan yang akan dibeli oleh pelanggan, jadi sebelum pemasangan saya memutuskan untuk menghabiskan waktu mengotomatiskan kalibrasi pelacakan.



Autocalibration



Sangat tidak nyaman untuk mengarahkan kamera, menggantung semua stiker ini, mengukur koordinat secara manual. Saya ingin menyingkirkan semua proses ini - menutup kamera dari buldoser, secara acak berjalan dengan penanda di luar angkasa dan menjalankan algoritme kalibrasi. Secara teori, ini harus dimungkinkan, tetapi bagaimana pendekatan penulisan algoritme tidak jelas.



Langkah pertama adalah memusatkan seluruh sistem. Alih-alih membagi area bermain menjadi blok-blok yang terdiri dari 8 kamera, saya membuat satu server, yang menerima koordinat titik pada bingkai semua kamera sekaligus.



Idenya adalah sebagai berikut:



  1. Saya menggantung kamera dan mengarahkannya ke area bermain dengan mata
  2. Saya memulai mode perekaman di server, di mana semua titik 2D yang berasal dari kamera disimpan ke file
  3. Saya berjalan di sekitar lokasi permainan yang gelap dengan penanda di tangan saya
  4. Saya berhenti merekam dan memulai penghitungan data kalibrasi, yang menghitung lokasi, orientasi, dan panjang fokus semua kamera.
  5. Sebagai hasil dari paragraf sebelumnya, diperoleh satu ruang yang diisi dengan kamera. Karena ruang ini tidak berlabuh ke koordinat nyata, ia memiliki offset dan rotasi acak, yang saya kurangi secara manual.


Saya harus menyekop sejumlah besar materi pada aljabar linier dan menulis ratusan baris kode Python. Begitu banyak sehingga saya hampir tidak ingat cara kerjanya.











Seperti inilah tampilan tongkat kalibrasi khusus yang dicetak pada printer.



Menguji proyek besar



Masalah dimulai selama pengujian di fasilitas tersebut beberapa minggu sebelum peluncuran proyek. Mengidentifikasi 8 warna penanda berbeda bekerja sangat buruk, pemain uji terus-menerus berteleportasi satu sama lain, beberapa warna tidak berbeda sama sekali dari sorotan eksternal di kompleks perbelanjaan. Upaya sia-sia untuk memperbaiki sesuatu dengan setiap malam tanpa tidur membuatku semakin putus asa. Semua ini diperparah dengan kurangnya kinerja server saat menghitung puluhan ribu garis lurus per detik.



Ketika tingkat kortisol dalam darah melebihi maksimum teoritis, saya memutuskan untuk melihat masalah dari sudut yang berbeda. Bagaimana Anda bisa mengurangi jumlah titik berwarna tanpa mengurangi jumlah penanda? Aktifkan pelacakan. Biarlah setiap pemain, misalnya, selalu memiliki tanduk merah di tanduk kiri. Dan yang kedua terkadang menyala hijau saat ada perintah dari server sehingga pada satu waktu hanya dinyalakan oleh satu pemain. Ternyata lampu hijau akan tampak melompat dari satu pemain ke pemain lain, memperbarui pengikatan pelacakan ke lampu merah dan menyetel ulang kesalahan orientasi magnetometer.



Untuk melakukan ini, saya harus lari ke chipidip terdekat, membeli LED, kabel, transistor, besi solder, pita listrik, dan menggantung fungsi kontrol LED di papan setelan, yang tidak dirancang untuk ini, pada ingus. Ada baiknya ketika memasang kabel papan, untuk berjaga-jaga, saya menggantungkan beberapa kaki stm-ki gratis pada bantalan kontak.







Algoritme pelacakan harus sangat rumit, tetapi pada akhirnya berhasil! Teleportasi para pemain satu sama lain menghilang, beban pada prosesor turun, suar berhenti mengganggu.





Proyek ini berhasil diluncurkan, pertama-tama saya membuat papan setelan baru dengan dukungan pelacakan aktif, dan kami melakukan pembaruan perangkat keras.







Bagaimana akhirnya?



Selama 3 tahun kami telah membuka banyak tempat hiburan di seluruh dunia, tetapi virus corona telah membuat penyesuaiannya sendiri, yang memberi kami kesempatan untuk mengubah arah kerja ke arah yang lebih bermanfaat secara sosial. Sekarang kami cukup berhasil mengembangkan simulator medis di VR. Tim kami masih kecil dan kami secara aktif berupaya untuk menambah staf kami. Jika ada pengembang UE4 berpengalaman yang sedang mencari pekerjaan di antara pembaca Habr, kirimkan surat kepada saya.







Momen lucu tradisional di akhir artikel:



Secara berkala, selama tes dengan sejumlah besar pemain, kesalahan muncul di mana pemain tiba-tiba diteleportasi untuk waktu yang singkat ke ketinggian beberapa meter, yang menyebabkan reaksi yang sesuai. Ternyata model kamera saya mengasumsikan perpotongan matriks dengan garis tak terhingga yang berasal dari penanda. Namun dia tidak memperhitungkan bahwa kamera tersebut memiliki bagian depan dan belakang, sehingga sistem mencari perpotongan garis tak berujung, meskipun titik tersebut berada di belakang kamera. Oleh karena itu, terdapat situasi ketika dua kamera yang berbeda melihat dua penanda yang berbeda, tetapi sistem mengira itu adalah satu penanda pada ketinggian beberapa meter.







Sistem ini benar-benar bekerja melalui pantat.



All Articles