Saturday, July 12, 2014

Trial setter and text-based UI

I've written the 'trial setter' that I described in my previous post. To recap, I had previously built tools that allowed primitive user interaction with the arduino: the user could echo commands to the arduino by typing them at the command prompt. For instance, typing echo "FORCE R" > TO_DEV would tell the arduino to deliver only stimuli that mean "choose the right port". We use this in the lab to force the subject to alternate between choosing left and choosing right, in an early stage of training. But it can be tedious to type in all of these commands manually, so why not automate it?

That's what the trial setter does. It reads the history of events in 'ardulines' and sends commands automatically to the arduino. For instance, it will force right trials until 5 rewards have been obtained, then force left trials until 5 rewards have been obtained, and so forth.

Here's what that code looks like:


It's a bit funny-looking, because it uses those persistent global variables. That's because the idea is that something calls this update() function over and over again, as often as possible, and on each call it needs to remember its current state (for instance, which side was most recently forced). 

What's going to call that update() function over and over? And what if the user wants to change the number of rewarded trials necessary to trigger a switch? We commonly start with long strings of rewarding the same side, and then decrease the length of this string as the subject improves. To address these questions, I wrote a simple text-based UI using the curses module.

I had never used curses before, but it's a really easy way to make simple text-based UIs. It's also pleasingly anachronistic, at least to me, and reminds me of the way I used to write BASIC programs in the 90s. Later on I'll upgrade this to something graphical, but that's a whole new can of worms.



Anyway, the UI provides a menu of options which can be accessed by pressing a single key. Some of them then require additional input. For instance, the screen shot shows how a user can change the number of rewards necessary to trigger a switch, by first pressing s and then typing in 25 at the prompt.

I also included shortcuts for other common actions, like manually rewarding a certain side or echoing arbitrary text to the arduino. Now the user doesn't actually have to type in echo commands in the terminal, which actually ends up saving a lot of keystrokes and aggravation in the long run.

This is all a layer of abstraction above the language I had previously implemented for the user to communicate with the arduino. Basically, it takes in user-friendly actions ("press R to reward the right port") and converts them into text commands that are easier for the arduino to interpret.

Here's the main code for doing this:

And a few helper functions:

Curses simplifies the processing of receiving keyboard input and writing text to the screen. The tricky part, as always, is the timing. Currently it waits for the user to press a key, but only up to a second. Then, since nothing is happening, it calls the update() function described above to run the trial setter. Then repeat this process forever. Once the user actually presses a key, it enters a blocking mode as necessary, to receive additional input for instance.

The next steps are to build in some more interesting logic in the trial setter. As the behavioral task becomes more complicated, we'll want to do more than just alternate sides. I'll probably also put some time into packaging up all of the different components into something cleaner and better documented.

No comments:

Post a Comment