Интеграция 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 на уровне протоколов. Гарантируем поддержку после сдачи — фиксы и доработки в течение месяца.







