Search code examples
matlabserial-portslidermatlab-guidepopupmenu

Matlab GUI - How to send a dynamically formatted string via serial?


I'm trying to send a string, composed of characters and a decimal number, via serial using fprintf. The format of the string I'd like to send is the following:

Roll,Cons,Kp,3.12

  • The first and the second words depend on the state (or better value) of a popup menu.

  • The number to send is the value of a slider called pidKpSlider that is part of GUI shown below.

enter image description here

The callback code of the slider:

function pidKpSliderCallBack(src,eventData)
   set(pidKpVal,'String',get(pidKpSlider,'Value'));
   fprintf(xbee,'%s,%s,%s,%.2f','Roll','Cons','Kp',get(pidKpSlider,'Value')); 
end

As I move the slider, the value in the text box is updated correctly but the string isn't sent. The callback code returns the following error.

Connection established. Rock & Roll!
You are in PID mode 
Error using serial/fprintf (line 115)
Too many input arguments.

Error in ControlBoard1_35/pidKpSliderCallBack (line 402)
       fprintf(xbee,'%s,%s,%s,%.2f','Roll','Cons','Kp',get(pidKpSlider,'Value'));

How can I correctly send the string?

Solution

Declare 2 global string functions

global pidStrategy;
global pidModeStrategy;

% Initialize them to U (which stands for unset)
pidStrategy = 'U';
pidModeStrategy = 'U';

PopMenus

pidPopup = uicontrol('Style','popupmenu','Position', [370 325 150 30],... 
    'String','Select|Roll|Pitch|Yaw|Altitude','visible','off', ...
    'Parent',hTabs(4), 'Callback',@pidPopupCallback);

pidModePopup = uicontrol('Style','popupmenu','Position', [370 280 150 30],... 
    'String','Select|Conservative|Aggressive','visible','off', ...
    'Parent',hTabs(4), 'Callback',@pidModePopupCallback);

PopMenu callback functions

%# drop-down pid menu callback
function pidPopupCallback(src,~)
    %# update plot color
    val = get(src,'Value');

    % Roll Pid Selected
    if val == 1
       pidStrategy = 'U';
       %disp('Unset');
    end

    % Roll Pid Selected
    if val == 2
       pidStrategy = 'Rol';
       %disp('Rol');
    end

    % Pitch Pid Selected
    if val == 3
       pidStrategy = 'Pit';  
       %disp('Pit');            
    end

    % Yaw Pid Selected
    if val == 4
       pidStrategy = 'Yaw';
       %disp('Yaw');
    end

    % Altitude Pid Selected
    if val == 5
       pidStrategy = 'Alt';
       %disp('Alt');
    end
end

%# drop-down pid Mode menu callback
function pidModePopupCallback(src,~)
    %# update plot color
    val = get(src,'Value');
    % Roll Pid Selected
    if val == 1
       pidModeStrategy = 'U';
       %disp('Unset');
    end

    % Conservative Mode Selected
    if val == 2
       pidModeStrategy = 'Cons';
       %disp('Con');
    end

    % Aggressive Mode Selected
    if val == 3
       pidModeStrategy = 'Agg'; 
       %disp('Agg');
    end
end

Slider Code:

% Text Box to show the value of the slider
pidKpVal = uicontrol('Style','text', 'String','AS', ...
    'Position', [484 56 40 25],'Visible','off',...
    'Parent',hTabs(4), 'FontSize',13,'FontWeight','normal');

%Slider and listener
pidKpSlider = uicontrol('Style','slider','Visible','off',...
'min',0,'max',2,'Callback',@(s,e) disp('KpSlider'),...
'SliderStep',[0.01 0.10],'Position', [140 185 350 20]);
KpListener = addlistener(pidKpSlider,'Value','PostSet',@pidKpSliderCallBack);

Slider Callback

function pidKpSliderCallBack(src,eventData)
   set(pidKpVal,'String',get(pidKpSlider,'Value')); 
   % send value only if the popup menu are correctly set
   if ~strcmp(pidStrategy,'U') && ~strcmp(pidModeStrategy,'U')
   strindToSend = [pidStrategy,',',pidModeStrategy,',Kp,',num2str(get(pidKpSlider,'Value'))]
   fprintf(xbee,'%s',strindToSend,'sync'); 
   end
end

The result is exactly what I was looking for! The program sends via serial decimal values corresponding to the cursor's position only if the options in the popmenus are set.


Solution

  • Looking at the documentation for fprintf (serial), you can only send one command, so you need to concatenate all your data into one command:

    fprintf(xbee,'Roll,Cons,Kp,%.2f',get(pidKpSlider,'Value'),'sync');
    

    You can't have multiple inputs, as you wrote your code.