Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Supported by

How to use coroutines with inline scripts ?

Hi all,

I am trying to use coroutines with an inline script. I read the documentation (https://osdoc.cogsci.nl/3.2/manual/structure/coroutines/) but I really don't get how to do it.

What I need to do is the following :

I am running my experiment in MRI, and I need to get the triggers sent by the MRI to write them in a file, and change what is shown to the participant accordingly.

While I wait for these triggers, my participant is able to answer using a response box. While trying the experiment in real conditions, it happened that the participant responded close to a trigger, so some triggers were missed.

For these reasons, I really need to have a script running in the background, waiting for keys. What I tried so far is the following :

I have a function my_coroutine() that I define at the beginning of my experiment, in the prepare tab. I want to get keys in this function and set global variables accordingly.

key_pressed = None
trigger_pressed = None
key_pressed_time = 0

def my_coroutine():
    global key_pressed
    global trigger_pressed
    global key_pressed_time

    yield
    
    while True:
        key, end_time = phase_1_keyboard.get_key(timeout=None)
        # If I got a trigger
        if key in trigger_keys:
            trigger_pressed = key
        # If I got a response
        else:
            key_pressed = key
            key_pressed_time = end_time

This generator is then called in a coroutines object in which I put the other script I want to run along with my coroutine.

In my inline script Display_target_1 that is triggered at each trial, I show a canvas, check if a trigger or a response key was pressed and do stuff accordingly.

canvas_trial.show()
while count_trigger < 3:
    if trigger_pressed:
        trigger_pressed = None
        list_to_write = [str(x) for x in (1, block+1, self.get("run_task1")+1, trial+1, count_trigger+1, end_time, exp.get("Condition"))]
        trigger_files[0].write("\t".join(list_to_write) + "\n")
        count_trigger += 1
    if key_pressed:
        key = key_pressed
        key_pressed = None
        if not response_given:
            var.Response_task1 = key
            var.Response_time_task1 = key_pressed_time - var.Begin_canvas_show
            canvas_trial['lure'].visible = False
            canvas_trial['target'].visible = False
            response_given = True

But when I launch my experiment, it seems I can't get past the initialize yield of my coroutine. Do you know what I am missing ?

Thanks for your help.

Jessica

Comments

  • Hi @Jessica Bourgin ,

    The reason that my_coroutine() blocks is that there's no yield statement inside the while loop, which is necessary for the function to suspend.

    However, this specific issue aside, I'm not sure that you're going about this in the right way. What exactly do you want to do? How do the key press (which I imagine is the trigger from the fMRI machine and not the participant's response?), the button box, and the canvas relate to each other?

    — Sebastiaan

  • edited September 2021

    Hi @sebastiaan,

    Thanks a lot for your quick answer. I forgot I tried this with a yield in the while loop of the coroutine as well, but the result was the same. I assumed I had something to do in my Display_target_1 as well but I could not figure out what.

    In particular, I tried to print "start" before the initialization yield, and "yield" after, and only "start" was printed. Therefore I assumed I had something to do in my Display_target_1 while loop.

    def my_coroutine():
        global key_pressed
        global trigger_pressed
        global key_pressed_time
    
        print("start")
        yield
        print("yield")
        
        while True:
            key, end_time = phase_1_keyboard.get_key(timeout=None)
            # If I got a trigger
            if key in trigger_keys:
                trigger_pressed = key
            # If I got a response
            else:
                key_pressed = key
                key_pressed_time = end_time
            keep_going = yield
            if not keep_going:
                break
    
    

    This aside, it's very probable that I am looking in the wrong direction. I assumed that using threads was what I needed but I couldn't manage to make it work. The problem I have to solve is the following:

    • I have triggers that are sent by the MRI every 2 seconds. These triggers are received by the keyboard of the OpenSesame computer as a keyboard input "t"
    • During the experiment, my participant is also able to respond when the canvas is presented. Their response on the response box is also received as a keyboard input: "b", "g" or "y".

    So the first issue I have is that a response and a trigger can occur at the "same" time, and so one of them can be missed.

    Finally, when I receive a trigger or a response, I need to react to them adequately and quickly:

    For triggers:

    • I would like to write them in a file for further data analysis (since this process must be quite heavy, I consider giving up on that if necessary).
    • I count them to know at which state of the trial I am. More precisely, each third trigger of a series ends the trial loop.

    For responses :

    • For the first response I get, I need to set the response and response time and hide elements of the canvas.

    So I thought that a way to do that could be to have a loop running in the background, listening to keyboard inputs and storing them in a cache.

    Then my trial loop could read that cache progressively and perform the appropriate actions (end trial, store response).

    So i am trying to find a way to do that, but maybe there is another option I did not consider?

    Thanks for your help.


    Best regards,

    Jessica

  • Hi Jessica,

    So I thought that a way to do that could be to have a loop running in the background, listening to keyboard inputs and storing them in a cache.

    That is indeed a bit complicated, because you essentially want to run your entire experiment as a co-routine. However, if the schedule is contingent on the fmri triggers, you can probably get away with separate co-routines per phase.

    So the first issue I have is that a response and a trigger can occur at the "same" time, and so one of them can be missed.

    For sakes of polling both fmri triggers and responses in parallel and treat them differently I suggest a while loop, as demonstrated in the attached example. Essentially, you are stuck in a loop for a certain amount of time, or until something predefined happens (e.g. a specific button press). Due to the loop, you can then dynamically adjust the presentation or other experimental factors.

    I would like to write them in a file for further data analysis

    I would not do that yet. Better store them in a list or so, and write them to file later. e.g. after a run. You can pickle it, or use pandas to write it to a csv file

    I count them to know at which state of the trial I am

    That is also quite easy. Essentially add a variable every time you detect a t response. Also here, you need to initialize the variable before you enter the main loop otherwise it will be reset every time a new loop starts. For other phases of the experiment you might need to do something similar in order to deal with the parallel polling of triggers and doing other experimental things.

    Anyway, I hope this helps you already a bit.

    good luck,

    Eduard

    Buy Me A Coffee

  • Hi @eduard,

    Thanks a lot for your response.

    The problem I have is that when I receive a response really close to a trigger, then a trigger (or a response) can be missed. It is not very probable (it seems that they need to be close by less than 10 ms) but it indeed happened during a pilot experiment. I precise that I tried it while removing the file writing process, so to lighten the instructions weight.

    So what I need is a way to detect if two keys are pressed exactly at the same time or at a very close time. Please tell me if this is not possible, I will then look for another way around (i.e., not listening to triggers during trials).

    I don't know if coroutines can help me with that, but in any case I don't know how to make them work with an inline_script in a coroutines item. I attach a basic example:

    I made a function my_coroutine, which I then use as a generator in the coroutines item. And when I run the experiment, I don't go past the initialisation yield of the coroutine, and can't figure out why.


    Thanks for your help.

    Best,

    Jessica

  • Hi Jessica,

    yeah, I see what you mean. Personally, I believe the chances for two events happening at the same time is so low, that I would not be too worried that this would happen (consistently) during the experiment. Anyway, I understand that it would be really really annoying if it happened, so it makes sense to try to minimize the chances of it happening. With respect to the co-routines, I can't help you much, as I have not much experience with them. That being said, I don't know whether they can be a key to your solution or not. If you insist on trying it with them, try to tag Sebastiaan (with an @ handle), he will be able to give you better directions with co-routines than I can.

    A couple more thoughts about no co-routine-solutions:

    • the response object might be useful as it stores all recent responses (that is keypresses). I haven't look into this in detail, but if you use a while loop as in the initial example, you should be able to see all responses that happened in that period, even if the occurred almost simultaneously.
    • generally, if you have trials of fixed lengths, you can build the logic of the while loop such that you only register all the keypresses (or TRs) without actually invoking any actions based on them. Only once the trial is over you can then start processing all the responses. That should facilitate a lag-less processing of all inputs. Again, the response object should give you guidance for this
    • even though it is nice to be able to confirm every single TR, I don't think it is necessary. Therefore, it is preferable to miss a TR rather than a response. Even a TR once in the beginning of a trial, could be sufficient for your needs.

    I hope this helps a bit.

    Best wishes,

    Eduard

    Buy Me A Coffee

Sign In or Register to comment.

agen judi bola , sportbook, casino, togel, number game, singapore, tangkas, basket, slot, poker, dominoqq, agen bola. Semua permainan bisa dimainkan hanya dengan 1 ID. minimal deposit 50.000 ,- bonus cashback hingga 10% , diskon togel hingga 66% bisa bermain di android dan IOS kapanpun dan dimana pun. poker , bandarq , aduq, domino qq , dominobet. Semua permainan bisa dimainkan hanya dengan 1 ID. minimal deposit 10.000 ,- bonus turnover 0.5% dan bonus referral 20%. Bonus - bonus yang dihadirkan bisa terbilang cukup tinggi dan memuaskan, anda hanya perlu memasang pada situs yang memberikan bursa pasaran terbaik yaitu http://45.77.173.118/ Bola168. Situs penyedia segala jenis permainan poker online kini semakin banyak ditemukan di Internet, salah satunya TahunQQ merupakan situs Agen Judi Domino66 Dan BandarQ Terpercaya yang mampu memberikan banyak provit bagi bettornya. Permainan Yang Di Sediakan Dewi365 Juga sangat banyak Dan menarik dan Peluang untuk memenangkan Taruhan Judi online ini juga sangat mudah . Mainkan Segera Taruhan Sportbook anda bersama Agen Judi Bola Bersama Dewi365 Kemenangan Anda Berapa pun akan Terbayarkan. Tersedia 9 macam permainan seru yang bisa kamu mainkan hanya di dalam 1 ID saja. Permainan seru yang tersedia seperti Poker, Domino QQ Dan juga BandarQ Online. Semuanya tersedia lengkap hanya di ABGQQ. Situs ABGQQ sangat mudah dimenangkan, kamu juga akan mendapatkan mega bonus dan setiap pemain berhak mendapatkan cashback mingguan. ABGQQ juga telah diakui sebagai Bandar Domino Online yang menjamin sistem FAIR PLAY disetiap permainan yang bisa dimainkan dengan deposit minimal hanya Rp.25.000. DEWI365 adalah Bandar Judi Bola Terpercaya & resmi dan terpercaya di indonesia. Situs judi bola ini menyediakan fasilitas bagi anda untuk dapat bermain memainkan permainan judi bola. Didalam situs ini memiliki berbagai permainan taruhan bola terlengkap seperti Sbobet, yang membuat DEWI365 menjadi situs judi bola terbaik dan terpercaya di Indonesia. Tentunya sebagai situs yang bertugas sebagai Bandar Poker Online pastinya akan berusaha untuk menjaga semua informasi dan keamanan yang terdapat di POKERQQ13. Kotakqq adalah situs Judi Poker Online Terpercayayang menyediakan 9 jenis permainan sakong online, dominoqq, domino99, bandarq, bandar ceme, aduq, poker online, bandar poker, balak66, perang baccarat, dan capsa susun. Dengan minimal deposit withdraw 15.000 Anda sudah bisa memainkan semua permaina pkv games di situs kami. Jackpot besar,Win rate tinggi, Fair play, PKV Games