Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Unable to send soft code manually
Hi Josh,

I am trying to add a feature for manually delivering water reward in a protocol for habituation (spontaneous licking triggers reward). I am using TrialManager and my main loop looks like this:

%% Main trial loop
for currentTrial = 1:MaxTrials

   if BpodSystem.Status.BeingUsed == 0; return; end % If user hit console "stop" button, end session
   [sma, S] = PrepareStateMachine(S); % Prepare next state machine.
   % Since PrepareStateMachine is a function with a separate workspace, pass any local variables needed to make
   % the state machine as fields of settings struct S e.g. S.learningRate = 0.2.
   SendStateMachine(sma, 'RunASAP'); % With TrialManager, you can send the next trial's state machine while the current trial is ongoing
   RawEvents = TrialManager.getTrialData; % Hangs here until trial is over, then retrieves full trial's raw data
   if BpodSystem.Status.BeingUsed == 0; return; end % If user hit console "stop" button, end session
   HandlePauseCondition; % Checks to see if the protocol is paused. If so, waits until user resumes.
   TrialManager.startTrial(); % Start processing the next trial's events (call with no argument since SM was already sent)
   %If trial data was returned from last trial, update plots and save data
   if ~isempty(fieldnames(RawEvents)) % If trial data was returned from last trial, update plots and save data
       BpodSystem.Data = AddTrialEvents(BpodSystem.Data,RawEvents); % Computes trial events from raw data
       BpodSystem.Data.TrialSettings(currentTrial) = S; % Adds the settings used for the current trial to the Data struct (to be saved after the trial ends)
       % define outcome types
       if ~isnan(BpodSystem.Data.RawEvents.Trial{currentTrial}.States.reward(1))
           Outcomes(currentTrial) = 1; % Hit
           Outcomes(currentTrial) = 2; % Miss
       BpodSystem.Data.Outcomes = Outcomes;
       % Update online plots
       lick_responses_plot(BpodSystem.Data, currentTrial, MaxTrials)
       trial_outcome_plot(Outcomes, currentTrial,f)
       % Saves the field BpodSystem.Data to the current data file

and my state machine looks like this:
function [sma, S] = PrepareStateMachine(S)

S = BpodParameterGUI('sync', S); % Sync parameters with BpodParameterGUI plugin

sma = NewStateMachine(); % Initialize new state machine description
sma = SetGlobalTimer(sma, 'TimerID', 1, 'Duration', 1);  % set response window

sma = AddState(sma, 'Name', 'trial_start', ...
   'Timer', 0,...
   'StateChangeConditions', {'GlobalTimer1_End', 'exit','BNC1High', 'reward','SoftCode1','reward'},...
   'OutputActions', {'GlobalTimerTrig',1});

sma = AddState(sma, 'Name', 'reward', ...
   'Timer', S.GUI.Rewad_Amount,...
   'StateChangeConditions', {'Tup', 'continue_trial'},...
   'OutputActions', {'Valve1',1 });

sma = AddState(sma, 'Name', 'continue_trial', ...
   'Timer', 0,...
   'StateChangeConditions', {'GlobalTimer1_End', 'exit','SoftCode1','reward'},...
   'OutputActions', {});

However, there is no response when I input SendBpodSoftCode(1) in the MATLAB command window during the trial. When I terminate the session, I got an error message saying "Error sending soft code:Bpod must be in a trial". I am quite confused because I was sending the soft code during a trial. 

Do you have any idea how I could solve this problem? 

Thank you in advance.

Hi Tin,

Could you please send your protocol .m file to
I'll try to replicate the issue here, and I want to make sure I have the same exact code.

Hi Josh,

I just sent my protocol file to the above email address.

Thanks a lot!

Hi Tin,

The issue is that your main loop is a loop. The TrialManager class allows other commands in your main loop to run while the trial is running, but the MATLAB prompt in the command window can't inject commands because MATLAB is still running your main loop (try with a command like disp('Hi')).

One way to create a manual override is to use a GUI button callback. The ParameterGUI plugin makes this easy; in the LightChasing example protocol, we create a pushbutton in the parameter GUI by setting a 'Style'. In the example protocol, the pushbutton callback targets a custom function, but it could just as easily target 'SendBpodSoftCode() directly. If you add the following two lines to the section of your code where you set up your parameters struct, it should work:

   S.GUI.SendSoftCode1 = 'SendBpodSoftCode(1)';
   S.GUIMeta.SendSoftCode1.Style = 'pushbutton';

This approach will require one button for each code. If you need to send an arbitrary byte, you can set up a separate GUI window in your protocol file with an edit box and a pushbutton. The pushbutton callback should read the contents of the edit box, convert from string to double, and pass it to SendBpodSoftCode().

I hope this helps!

Hi Josh, 

This is working perfectly. Thank you very much!


Forum Jump: