Інтеграція UHF RFID-сканера: від BLE-підключення до production
UHF RFID (860–960 МГц) дозволяє читати пасивні мітки на відстані до 10 метрів і сотні тегів за секунду. На відміну від HF NFC (до 10 см), це принципово для складських завдань. Ми стикаємося з ситуаціями, коли замовнику потрібно прив'язати Zebra RFD40 або Chainway R6 до мобільного застосунку для інвентаризації чи логістики. Типовий біль — нерозуміння, який протокол обрати (LLRP чи пропрієтарний SDK), як обійти обмеження частотних діапазонів і не втратити продуктивність. У цій статті — конкретний досвід і код для Android (Kotlin), який можна адаптувати під iOS та Flutter. Розберемо типові помилки та покажемо робочі конфігурації на прикладі Zebra RFD40.
Як обрати протокол: LLRP чи пропрієтарний SDK?
LLRP (Low Level Reader Protocol, стандарт ISO 15961) — універсальний протокол керування UHF-рідерами. Підтримують Impinj, Zebra, Alien. Дозволяє використовувати один код для різних рідерів, але потребує Wi-Fi-підключення до стаціонарного обладнання. Для мобільних BLE-рідерів LLRP не підходить — там потрібен пропрієтарний SDK.
Пропрієтарний SDK — Zebra RFID SDK, Chainway SDK. Простіший в інтеграції, працює по BLE або USB, але прив'язує до вендора. Зате дає доступ до кнопки тригера, керування живленням і подіям у реальному часі.
| Характеристика | LLRP | Пропрієтарний SDK (Zebra) |
|---|---|---|
| Підключення | Wi-Fi / Ethernet | BLE / USB |
| Мобільні рідери | Ні | Так (RFD40, TC21) |
| Кроссплатформенність | Так | Тільки під платформу SDK |
| Складність | Висока | Середня |
| Швидкість інтеграції | Тиждень+ | 3–5 днів |
Для мобільних UHF-рідерів з BLE ми завжди рекомендуємо пропрієтарний SDK — це економить час і дає повний контроль над пристроєм.
Zebra RFID SDK: практичне впровадження
Розглянемо інтеграцію Zebra RFD40 на Android з використанням rfid-api3. Код нижче демонструє підключення, налаштування потужності та фільтрацію за EPC.
implementation("com.zebra.rfid.api3:rfid-api3:2.0.2.109")
class UhfReaderManager(private val context: Context) : RfidEventsListener {
private var reader: RFIDReader? = null
private val readers = Readers(context, ENUM_TRANSPORT.BLUETOOTH)
fun connect(deviceName: String) {
val readerDevices = readers.GetAvailableRFIDReaderList()
val targetDevice = readerDevices?.find { it.name == deviceName } ?: return
reader = targetDevice.RFIDReader
reader?.connect()
// Налаштування параметрів зчитування
val params = reader?.Config?.antennaConfigurations?.get(0)
params?.transmitPowerIndex = 270 // ~30 dBm, максимальна потужність
params?.receiveFrequency = 55 // оптимально для більшості регіонів
reader?.Config?.setAntennaConfiguration(params)
// Події
reader?.Events?.apply {
addEventsListener(this@UhfReaderManager)
setHandheldEvent(true) // кнопка тригера на рідері
setTagReadEvent(true)
setInventoryStartEvent(true)
setInventoryStopEvent(true)
}
}
// Запуск інвентаризації з фільтрацією за маскою EPC
fun startInventoryWithFilter(epcMask: String?) {
val startTrigger = TriggerInfo().apply {
startTrigger.triggerType = START_TRIGGER_TYPE.START_TRIGGER_TYPE_IMMEDIATE
}
val stopTrigger = TriggerInfo().apply {
stopTrigger.triggerType = STOP_TRIGGER_TYPE.STOP_TRIGGER_TYPE_DURATION
stopTrigger.stopTriggerByDuration.duration = 5000 // 5 секунд
}
val tagFilter = if (epcMask != null) {
TagFilter().apply {
tagPattern = epcMask
tagPatternBitCount = epcMask.length * 4
filterAction = FILTER_ACTION.FILTER_ACTION_STATE_AWARE_FILTERING_ACTION_UNSPECIFIED
}
} else null
reader?.Actions?.Inventory?.perform(startTrigger, stopTrigger, tagFilter)
}
override fun eventReadNotify(e: RfidReadEvents) {
e.ReadEventData.TagData.forEach { tag ->
onTagRead(
epc = tag.TagID,
rssi = tag.PeakRSSI.toInt(),
antennaId = tag.AntennaID.toInt(),
readCount = tag.ReadCount
)
}
}
override fun eventStatusNotify(rfidStatusEvents: RfidStatusEvents) {
when (rfidStatusEvents.StatusEventData.statusEventType) {
STATUS_EVENT_TYPE.INVENTORY_START_EVENT -> onInventoryStarted()
STATUS_EVENT_TYPE.INVENTORY_STOP_EVENT -> onInventoryCompleted()
STATUS_EVENT_TYPE.HANDHELD_TRIGGER_EVENT -> {
val triggerType = rfidStatusEvents.StatusEventData.HandheldTriggerEventData.handheldEvent
if (triggerType == HANDHELD_TRIGGER_EVENT_TYPE.HANDHELD_TRIGGER_PRESSED) {
startInventoryWithFilter(null)
}
}
}
}
}
transmitPowerIndex = 270 — потужність в одиницях рідера. У кожного виробника своя шкала. Zebra RFD40: 0–270 = 0–30 dBm. Надмірна потужність у закритому складі → перевідбиття → хибні зчитування з сусідніх зон.
Як налаштувати регіональні частоти?
UHF RFID працює в різних діапазонах:
- США/Канада (FCC): 902–928 МГц
- Європа/Росія (ETSI): 865–868 МГц
- Китай: 920–925 МГц
Мобільний застосунок має встановлювати регіон рідера:
reader?.Config?.setRegulatoryConfig(
RegulatoryConfig().apply {
region = REGULATORY_REGION.REGULATORY_REGION_ETSI // або FCC, China
enableHoppingChannels = true
}
)
Використання FCC-діапазону в Росії — порушення РЧС. Сучасні рідери блокують невірний регіон апаратно, але ми завжди перевіряємо відповідність перед запуском.
Продуктивність: 500 тегів за секунду без лагів
Потік тегів не можна обробляти на головному потоці — UI заморозиться. Використовуємо корутини та канали:
private val tagChannel = Channel<TagReadData>(capacity = Channel.UNLIMITED)
// У BroadcastReceiver/callback рідера — тільки кладемо в канал
override fun eventReadNotify(e: RfidReadEvents) {
e.ReadEventData.TagData.forEach { tag ->
tagChannel.trySend(tag) // не блокує, не кидає виняток
}
}
// Обробка в окремій корутині
fun processTagsInBackground() {
scope.launch(Dispatchers.Default) {
for (tag in tagChannel) {
val epc = tag.TagID
inventoryRepository.recordRead(epc, tag.PeakRSSI.toInt())
}
}
}
Такий підхід гарантує, що UI залишається чуйним навіть при піковому навантаженні. На iOS аналогічний результат дає OperationQueue з maxConcurrentOperationCount = 1.
Процес інтеграції
- Аналіз вимог — вибір рідера (Zebra, Chainway, Bluebird), визначення сценаріїв (інвентаризація, приймання, відвантаження).
- Підготовка SDK — отримання ключів, налаштування середовища (Android Studio, Xcode).
- Розробка модуля зв'язку — підключення по BLE, обробка подій, фільтрація.
- Тестування на реальних мітках — перевірка дальності, потужності, регіональних налаштувань.
- Оптимізація продуктивності — фонові потоки, буферизація, синхронізація з сервером.
- Деплой в App Store / Google Play + TestFlight для бета-тесту.
Що входить у роботу
- Підключення та налаштування вибраного UHF-рідера
- Реалізація зчитування з фільтрацією за EPC та RSSI
- Обробка подій тригера та інвентаризації
- Підтримка регіональних частот (FCC/ETSI/Китай)
- Оптимізація продуктивності (фонові потоки, буферизація)
- Інтеграція з вашою WMS/ERP через REST або GraphQL
- Надання вихідного коду та документації
- Місяць безкоштовної підтримки після здачі
Терміни
Базова інтеграція одного BLE-рідера з відображенням тегів — від 5 днів. Розширене рішення з регіональним налаштуванням, синхронізацією та фільтрацією — 1–2 тижні. Оцінимо ваш проєкт безкоштовно — зв'яжіться для обговорення деталей.
Чому варто довіритися нашому досвіду
Ми реалізували понад 50 проєктів з UHF RFID на мобільних платформах, включаючи інтеграцію з 1С, SAP та WMS-системами. Наші інженери мають сертифікати з Android та iOS, а також досвід роботи з Bluetooth LE на рівні протоколів. Гарантуємо підтримку після здачі — фікси та доопрацювання протягом місяця.







