Привет, любители Habr! По счастливой случайности в августе 2018 года мне посчастливилось вместе с моим товарищем(kirillskiy) начать работать над потрясающим по своей интересности проектом. И вот, днем мы были обычными программистами, а ночью с?у?п?е?р?г?е?р?о?я?м?и? снова программистами, которые бьются над вопросами распознавания движений для людей имеющих ограничения функциональности своих конечностей, естественно этим могли бы пользоваться и здоровые люди, используя подобную технологию самыми разными способами.
В этой статье, Кирилл в общих чертах рассказывает о проекте, я же расскажу подробнее и затрону тему андроида в нем.
Расскажу вначале о проекте целиком, что мы напридумывали и как захотели реализовать это:
1) Была выбрана ЭМГ( Электромиография — регистрация электрической активности мышц) как способ получения данных( о, да, данных будет много). Впервые данный способ был применен в 1907 году, поэтому мы шли проторенной дорогой.
2) Нашли 8-ми канальный ЭМГ датчик работающий по bluetooth(даже имеющий свой API, которое в итоге, оказалось абсолютно бесполезным, ибо пришлось самостоятельно коннектиться как BT устройству. Спасибо хоть спецификацию написали)
3) Мы решили, что работать все будет так:
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())
}
}
}
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()
}
})
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)
}
.....
К сожалению, не доступен сервер mySQL