Android, Rx, dan Kotlin, atau cara membuat cakar Lego menyusut. Bagian 1

Hai, pecinta Habr! Secara kebetulan, pada bulan Agustus 2018, saya beruntung mulai bekerja dengan teman saya ( kirillskiy ) pada sebuah proyek yang sangat menarik minatnya. Jadi, pada siang hari kami adalah programmer biasa, dan pada malam hari kami adalah programmer lagi yang berjuang dengan masalah mengenali gerakan untuk orang-orang dengan fungsi terbatas anggota tubuh mereka, orang sehat secara alami juga dapat menggunakan ini menggunakan teknologi serupa dengan berbagai cara.

Dalam artikel ini , Cyril secara umum berbicara tentang proyek tersebut, tetapi saya akan menceritakan lebih detail dan menyentuh topik android di dalamnya.
Pertama, saya akan memberi tahu Anda tentang keseluruhan proyek, apa yang kami buat dan bagaimana kami ingin menerapkan ini:

1) EMG (Elektromiografi - merekam aktivitas listrik otot) dipilih sebagai cara untuk mendapatkan data (oh, ya, akan ada banyak data). Untuk pertama kalinya metode ini diterapkan pada tahun 1907, jadi kami berjalan di sepanjang jalur.

2) Kami menemukan sensor EMG 8-channel yang bekerja pada bluetooth (bahkan memiliki API sendiri, yang pada akhirnya ternyata sama sekali tidak berguna, karena saya harus terhubung sebagai perangkat BT sendiri. Terima kasih setidaknya kami menulis spesifikasi)

3) Kami memutuskan bahwa semuanya akan berfungsi seperti ini:

  • mode pelatihan. Kami mendandani sensor di lengan, pilih jenis gerakan yang akan kami latih. Misalnya ... "menekuk sikat." dan mulai pelatihan (ulangi gerakan 12 kali). Kami akan menyimpan data yang diterima saat ini dan kemudian mengirimkannya ke server, di mana kami akan melatih jaringan saraf (dengan tenang, saya akan memberitahu Anda tentang ini juga)
  • Mode pengenalan gerakan langsung. Data yang diambil selama gerakan dibandingkan dengan model yang diperoleh sebagai hasil pelatihan jaringan saraf. Berdasarkan hasil, kita akan mendapatkan "BENDING BRUSH", misalnya.
  • mode mengemudi. Menurut jenis gerakan tertentu, sesuatu harus dibuat untuk bergerak. Sebagai contoh, seorang manipulator berkumpul di dapur dari seorang desainer (PPC, seberapa mahal) dari sebuah pabrikan Denmark yang terkenal.

4) item Android. Saya adalah seorang pengembang Android - dan itu adalah dosa untuk tidak menggunakannya. Android ada di sini bersama kami:

  • menemukan semua perangkat BT yang tersedia
  • terhubung ke sensor
  • menggambar grafik berdasarkan data yang diambil dari sensor (8 saluran, frekuensi 200Hz). 8 kurva yang indah dan berwarna-warni.
  • mengimplementasikan mode pelatihan (pemilihan jenis gerakan terlatih, tombol mulai pelatihan, tombol pengiriman data)
  • mengimplementasikan interaksi client-server. Penting untuk mengirim data ke server sehingga jaringan saraf dilatih
  • mengimplementasikan koneksi dan interaksi dengan Raspberry PI 3B, dimana motor disolder, yang menggerakkan manipulator dalam gerakan.

5) Raspberry PI 3B. raspberry yang kami gunakan untuk Android Things, dan kemudian kami mengangkat server BT di atasnya, yang menerima pesan dari perangkat Android dan menggerakkan motor yang sesuai, yang menggerakkan super-cakar dari LEGO.

6) Server. Ini digunakan oleh Docker secara lokal di komputer. Ini menerima data yang dikirim oleh perangkat Anda, mengajarkan jaringan saraf, dan mengembalikan model.

Bagian nomor 1. Android. Kali ini kami akan mempertimbangkan kap proyek tentang Android hingga data dikirim ke server.

Ini disebut NUKLEOS (https://github.com/cyber-punk-me/nukleos)
Tumpukan:

- Kotlin
- MVP
- Belati2
- Retrofit2
- RxKotlin, RxAndroid

untuk raspberry:

-Android Things

Di tempat kerja, mereka tidak membiarkan saya bermain dengan arsitektur, tetapi akhirnya saya mendapat kesempatan untuk bermain dengan mainan lama bernama MVP.

Aplikasi ini terdiri dari satu gaya aktivitas Navigasi Bawah dan 4 fragmen:
Yang pertama adalah "Daftar semua perangkat BT yang tersedia"

Kami memilih sensor BT 8-channel, yang memiliki API sendiri untuk bekerja dengan BT. Sayangnya, api itu ternyata benar-benar tidak berguna, karena langsung menyarankan untuk mendefinisikan salah satu dari 6 jenis gerakan (seperti), tetapi akurasi pengenalannya 80% - dan itu tidak baik. Kami membutuhkan data aktual. Nilai perubahan dalam potensi bioelektrik yang terjadi pada otot manusia setelah eksitasi serat otot. Dan untuk ini perlu untuk bekerja dengan sensor ini secara langsung. Pencipta meninggalkan deskripsi protokol untuk bekerja dengannya, jadi mereka harus menggali sekitar untuk tidak begitu lama. Saya bisa menggambarkan contoh bekerja dengan perangkat BT telanjang di artikel terpisah, jika itu menarik, tetapi singkatnya terlihat seperti ini:

class BluetoothConnector(val context: Context) { private val mBTLowEnergyScanner by lazy { (context.getSystemService(Activity.BLUETOOTH_SERVICE) as BluetoothManager) .adapter.bluetoothLeScanner } private var mBluetoothScanCallback: BluetoothScanCallback? = null // scan. fun startBluetoothScan(serviceUUID: UUID?) = Flowable.create<BluetoothDevice>({ mBluetoothScanCallback = BluetoothScanCallback(it) if (serviceUUID == null) { mBTLowEnergyScanner.startScan(mBluetoothScanCallback) } else { mBTLowEnergyScanner.startScan( arrayListOf(ScanFilter.Builder().setServiceUuid(ParcelUuid(serviceUUID)).build()), ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(), mBluetoothScanCallback) } }, BackpressureStrategy.BUFFER).apply { doOnCancel { mBTLowEnergyScanner.stopScan(mBluetoothScanCallback) } } // scan with timeout fun startBluetoothScan(interval: Long, timeUnit: TimeUnit, serviceUUID: UUID? = null) = startBluetoothScan(serviceUUID).takeUntil(Flowable.timer(interval, timeUnit)) inner class BluetoothScanCallback(private val emitter: FlowableEmitter<BluetoothDevice>) : ScanCallback() { override fun onScanResult(callbackType: Int, result: ScanResult?) { super.onScanResult(callbackType, result) result?.let { it.device.apply { emitter.onNext(this) } } } override fun onScanFailed(errorCode: Int) { super.onScanFailed(errorCode) emitter.onError(RuntimeException()) } } } 

Bungkus layanan BT standar dengan hati-hati dalam RX dan kurangi rasa sakit.

Selanjutnya, jalankan pemindaian, dan terima kasih kepada rx pada berlangganan, kami membuat daftar semua perangkat dengan memasukkannya ke dalam RecyclerView:

 mFindSubscription = mFindFlowable ?.subscribeOn(Schedulers.io()) ?.observeOn(AndroidSchedulers.mainThread()) ?.subscribe({ if (it !in mBluetoothStuffManager.foundBTDevicesList) { addSensorToList(SensorStuff(it.name, it.address)) mBluetoothStuffManager.foundBTDevicesList.add(it) } }, { hideFindLoader() showFindError() if (mBluetoothStuffManager.foundBTDevicesList.isEmpty()) { showEmptyListText() } }, { hideFindLoader() showFindSuccess() if (mBluetoothStuffManager.foundBTDevicesList.isEmpty()) { showEmptyListText() } }) 

Memilih salah satu perangkat, memilihnya, dan pergi ke layar berikutnya:
"Pengaturan Sensor"

Kami terhubung dengannya dan mulai mengalirkan data sensor menggunakan perintah yang telah kami siapkan sebelumnya. Untungnya, protokol untuk bekerja dengan perangkat ini oleh pencipta sensor dijelaskan:

 object CommandList { //Stop the streaming fun stopStreaming(): Command { val command_data = 0x01.toByte() val payload_data = 3.toByte() val emg_mode = 0x00.toByte() val imu_mode = 0x00.toByte() val class_mode = 0x00.toByte() return byteArrayOf(command_data, payload_data, emg_mode, imu_mode, class_mode) } // Start streaming (with filter) fun emgFilteredOnly(): Command { val command_data = 0x01.toByte() val payload_data = 3.toByte() val emg_mode = 0x02.toByte() val imu_mode = 0x00.toByte() val class_mode = 0x00.toByte() return byteArrayOf(command_data, payload_data, emg_mode, imu_mode, class_mode) } ..... 

Bekerja dengan perangkat ini juga dibungkus dengan hati-hati untuk bekerja tanpa rasa sakit.

Sensor mengembalikan Byte Arrays secara alami, dan itu perlu untuk memotong konverter, frekuensi sensor adalah 200 Hz ... jika itu menarik, saya dapat menggambarkannya secara detail (baik, atau melihat kode), tetapi pada akhirnya kami bekerja dengan jumlah data yang cukup besar dengan cara ini:

1 - Kita perlu menggambar kurva masing-masing sensor. Tentu saja, tidak ada gunanya menyerahkan semua data secara BENAR-BENAR, karena pada perangkat seluler tidak masuk akal bagi mata untuk memeriksa 200 perubahan per detik pada setiap sensor. Karena itu, kami tidak akan mengambil semuanya.

2 - Kita perlu bekerja dengan seluruh jumlah data, jika itu adalah proses pembelajaran atau pengenalan.

RX sangat cocok untuk kebutuhan ini dengan semua filternya.

Bagan harus dibuat. Siapa yang peduli - lihat PowerfullChartsView di folder views.

Dan sekarang beberapa video:


Dalam video Anda akan melihat bagaimana Cyril bekerja dengan sistem secara keseluruhan. Video sedang bekerja dengan model. Tapi modelnya ada di server. Di masa depan, tentu saja akan ada di perangkat, yang secara signifikan akan mempercepat respon)

Tuliskan aspek mana yang menarik, mana yang lebih rinci. Secara alami, kami sedang mengerjakan suatu proyek dan terbuka untuk saran Anda.

Seluruh proyek github ada di sini

Source: https://habr.com/ru/post/id438034/


All Articles