MATLAB toolbox for continuous RFID logging in animal-behaviour experiments. It polls one or more RFID readers, writes every tag detection to a single table, and produces a visit timeline and a set of visit statistics.
Two acquisition backends are supported, and any mix of them can run at the same time, one per COM port:
| Backend | Hardware | Link | Tag ID format |
|---|---|---|---|
arduino |
ID-20LA modules on an Arduino MEGA | USB serial, ASCII lines, up to 4 antennas | 12 hex characters |
dorset |
Dorset LID650N / LID665N | USB virtual COM, DLE-STX/ETX binary | 15-digit ISO FDX-B |
Every read is normalised into the same six-column table:
Port | PC_Timestamp_sec | Arduino_Timestamp_us | TagID | Reader | TagName
The analysis stages (colour map, timeline, statistics) consume only that table, so the acquisition backend does not affect downstream code.
- MATLAB R2021a or newer
- Instrument Control Toolbox (for
serialport) - At least one supported reader on a COM port
git clone https://github.com/JesusJBallesteros/MultiRFID.gitOpen the cloned folder in MATLAB and make it the current folder. Multiple_RFID.m
adds functions/ and config/ to the path itself; no permanent path changes are
needed.
- Connect the hardware.
- Arduino: upload a sketch from
Arduino Software/to each board. - Dorset: import
DORSET/LID650665 settings.xmlwith the manufacturer's software so the reader matches the configuration below.
- Arduino: upload a sketch from
- Verify each link before recording. Set
COM_PORTat the top of whichever test you run, then from the repository root:If a test prints nothing, the problem is the hardware link, not the toolbox.addpath functions arduino_link_test % prints the ASCII lines from an Arduino board dorset_link_test % prints the raw hex frames from a Dorset reader
- Declare your readers in
config/RFID_config.m(oneopt.readersentry per COM port) and your transponders inconfig/make_tag_names.m. - Run the session:
Multiple_RFID - Press
pto pause or resume andsto stop and save. The keyboard control window must have focus. - Collect the outputs from
log/.
Each run writes four files to opt.logDir, all sharing one timestamp:
| File | Contents |
|---|---|
rfid_log_<timestamp>.csv |
Every read, one row per detection |
rfid_log_<timestamp>.mat |
allData, devices, tagIDNames, opt |
visit_timeline_<timestamp>.png |
Detections per port and reader over time |
visit_stats_<timestamp>.png and .mat |
Visit counts, durations, co-presence, transitions |
Reference outputs from a two-backend test session are in examples/.
config/RFID_config.m returns the opt struct. Readers are declared one entry
per physical device; add, remove or comment out entries freely.
opt.readers(1).type = "dorset";
opt.readers(1).port = "COM3";
opt.readers(1).baudRate = 19200;
opt.readers(1).nAntennas = 1;
opt.readers(2).type = "arduino";
opt.readers(2).port = "COM4";
opt.readers(2).baudRate = 500000;
opt.readers(2).nAntennas = 4;Other fields:
| Field | Default | Meaning |
|---|---|---|
tagMapFile |
config/tag_names.mat |
Merged tag ID to subject label map |
useKeyInput |
true |
Open the pause/stop control window |
liveReport |
false |
Print each detection to the command window |
logDir |
<repo>/log |
Destination for logs and figures |
All tag names live in config/make_tag_names.m, which builds the merged
tagIDNames map used by both backends. The two ID namespaces do not overlap
(12 hex characters against 15 decimal digits), so one map covers a mixed
session without ambiguity.
Add a transponder by appending to the ids and labels lists of the matching
section, keeping the two aligned. A blank label is auto-named
<prefix>_UNLABELED_NN so an unassigned tag is still tracked end to end. The
function runs automatically on each session start.
Up to four modules per MEGA. Readers 1-3 use the hardware UARTs; reader 4 uses
SoftwareSerial.
| ID-20LA pin | Arduino MEGA pin | Purpose |
|---|---|---|
| VCC | 5V | Power |
| GND | GND | Ground, common to all modules |
| D0 (Tx) | 19 / 17 / 15 / 10 (Rx) | Data out, readers 1-4 |
| TIR | 2-5 | Tag in range, readers 1-4 |
| RES | 5V | Reset, active low |
| FORM | GND | Format select |
Power the antennas from an external supply to keep the drive current constant. The board streams to the host at 500000 baud; the reader UARTs run at 9600.
One USB connection per reader. Configure the reader for:
- 19200 baud
- ISO FDX-B only
- Decimal output, so the binary frame carries BCD digits
- Use-All-ID-Codes, which repeats a tag-present frame while the tag is in the field instead of emitting check-in/check-out pairs
DORSET/LID650665 settings.xml is an export of a working configuration.
Multiple_RFID.m Session entry point: open, poll, log, save, plot
config/
RFID_config.m Reader list and session options
make_tag_names.m Tag ID to subject label definitions
tag_names.mat Generated map, rebuilt on each run
functions/
newDeviceStruct.m Shared per-device record template
open_Readers.m Opens any mix of backends into one device array
open_Ports.m Opens one Arduino device
open_DorsetPorts.m Opens one Dorset device in binary mode
readDorsetFrames.m Non-blocking Dorset frame parser and BCD decode
arduino_link_test.m Standalone Arduino reception test
dorset_link_test.m Standalone Dorset reception test
buildColorMap.m Per-subject plotting colours
plotTimeline.m Detection timeline figure
computeVisitStats.m Visit metrics and statistics figure
DORSET/
LID665N_FDXB_Reader.m Standalone reference decoder
LID650665 settings.xml Reader configuration export
DsetDataBase.key Reader tag database export
Arduino Software/
MultiRFID_Reader_ID20LABoards/ Firmware for ID-20LA modules
MultiRFID_Reader_GroveBoards/ Firmware for Grove 125 kHz UART modules
examples/ Reference outputs from a test session
log/ Run outputs, not tracked
| Symptom | Check |
|---|---|
Port COM<n> not found |
Port number in Device Manager, or run serialportlist("available"). Close any other program holding the port. |
| No rows logged | Run the matching *_link_test.m. If it prints nothing, the problem is the link, not the toolbox. |
Every tag reads as UNKNOWN |
The ID is not listed in config/make_tag_names.m. The link tests print the raw IDs. |
Arduino streams only NONE |
No tag in range, or the TIR line is not wired to the configured pin. |
| Dorset frames appear but nothing is logged | Reader is not in Decimal / Use-All-ID-Codes mode; re-import the settings XML. |
Parts of the MATLAB code and of this documentation were drafted with the help of AI coding assistants. All of it was reviewed, adapted and validated against real hardware by the author, who is responsible for the contents of this repository.
If this software contributes to published work, please cite it using the
metadata in CITATION.cff.
GNU General Public License v3.0. See LICENSE.
Jesus J. Ballesteros, Department of Biopsychology, Ruhr-Universitat Bochum.