Most Arduino-compatible boards are full-speed USB devices, which limits how frequently it can send and receive data (usually in 1ms frames). AFAIK you could have multiple transactions in a frame with bulk transfers (which AFAIK is how serial-over-USB moves data), especially if nothing else is using the bus. The reality might be more variable, depending on what other USB things are going on. Here’s a nice diagram describing how USB transfers can be structured.
You might be limited on the OS/software side too. You can try to make sure that the process doing the USB transfers has higher priority (which may reduce variability), but my general impression is that Windows will have a bit more scheduling jitter compared to e.g. Linux-based systems.
A few ideas:
- There are some Arduino-compatible boards that can act as high-speed USB devices, e.g. the Teensy 4.0. That gets you a minimum service interval of 125us, instead of 1ms.
- If you’re using pyserial, you could try Psychtoolbox’s IOPort instead, which is accessible from the Python side. The guts are implemented in C, which might provide more reliable performance?
- Bump the priority of the process with PsychoPy’s
core.rush()
.