HC-SR04 Measures Really Slow in Simulink with Arduino IO(Legacy)

Hello everyone,

I'm trying to measure some distance with HC-SR04 on Matlab Simulink. And I want to do it by creating my own custom block on Arduino IO Package in Simulink.

What I did so far is,

Modified Adioes.m as below;
Included these lines at the beginning of the code

#include <NewPing.h>
NewPing sonar(12, 11, 200);

Also added these lines to the switch case:

case 400:
       int distance;
      
      delay(50);                     // Wait 50ms between pings (about 20 pings/sec). 29ms should be the 
                                         //I also tried without delay(50) line.
shortest delay between pings.
      distance = sonar.ping_cm(); 
      Serial.println(distance);
      s=-1;  /* we are done with the aux function so -1      */
      break;

I uploaded this code successfully to my Uno then added these lines to Arduino.m.

% Ultrasound
        function val=Ultrasound(a)
            
            % roundTrip(a,byte); sends something to the arduino and back
            % The first argument, a, is the arduino object.
            % The second argument, byte, is any integer from 0 to 255.
            % The output is the same byte, which was received from the
            % arduino and sent back along the serial connection unchanged.
            %
            % This is provided as an example for people that want to add
            % their own code to this arduino class (the section handling
            % this dummy function in the pde file is handled as "case 400:",
            % one might take the parameter, perform some potentially useful
            % operation, and then send any result back via serial connection).
            %
            % Examples:
            % roundTrip(a,48); % sends '48' to the arduino and back.
            % a.roundTrip(53); % sends '53' to the arduino and back.
            %
            
            %%%%%%%%%%%%%%%%%%%%%%%%% ARGUMENT CHECKING %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            
            % check arguments if a.chkp is true
%             if a.chkp,
%                 
%                 % check nargin
%                 if nargin~=2,
%                     error('Function must have one argument');
%                 end
%                 
%                 % check argument (must be a byte)
%                 errstr=arduino.checknum(byte,'byte',0:255);
%                 if ~isempty(errstr), error(errstr); end
%                 
%             end
%             
%             % check a.aser for validity if a.chks is true
%             if a.chks,
%                 errstr=arduino.checkser(a.aser,'valid');
%                 if ~isempty(errstr), error(errstr); end
%             end
            
            %%%%%%%%%%%%%%%%%%%%%%%%% SEND ARGUMENT ALONG %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            
            if strcmpi(get(a.aser,'Port'),'DEMO'),
                % handle demo mode
                
                % minimum analog output delay
                pause(0.0014);
                
                % sets the output
                %val=byte;
                
            else
                
                % check a.aser for openness if a.chks is true
                if a.chks,
                    errstr=arduino.checkser(a.aser,'open');
                    if ~isempty(errstr), error(errstr); end
                end
                
                % send mode and byte
                fwrite(a.aser,[88],'uchar');
                
                % get value back
                val=fscanf(a.aser,'%d');
                
            end
            
        end % Ultrasound

the line fwrite(a.aser,[88],'uchar'); simply sends "88" to Arduino via Serial and the number 88 triggers a case which is "400" in our case. After Arduino execute the "case 400" it sends the distance from sonar.ping_cm() line.

So lastly I create a msfunction to call with a block on simulink. Here it is the code for msfunction:

function msfun_arduino_ultrasound(block)
% Level-2 M-File S-Functions, Copyright 2014, The MathWorks, Inc.

% instance variables 
myArduino = [];
myPin = 0;

setup(block);

%% ---------------------------------------------------------

    function setup(block)
        % Register the number of ports.
        block.NumInputPorts  = 0;
        block.NumOutputPorts = 1;
        
        block.SetPreCompOutPortInfoToDynamic;
        block.OutputPort(1).Dimensions  = 1;
        block.OutputPort(1).SamplingMode = 'sample';
        
        % Set up the states
        block.NumContStates = 0;
        block.NumDworks = 0;
        
        % Register the parameters.
        block.NumDialogPrms     = 3; % arduinoVar, arduinoPin, Sample Time
        block.DialogPrmsTunable = {'Nontunable', 'Nontunable', 'Nontunable'};
        
        % Set the sample time
        block.SampleTimes = [block.DialogPrm(3).Data 0];
        
        block.SetAccelRunOnTLC(false); % run block in interpreted mode even w/ Acceleration
        block.SimStateCompliance = 'DefaultSimState';
                
        % the ArduinoIO Setup block uses the Start method to initialize the arduino
        % connection; by using InitConditions, we ensure that we don't access
        % the variable before it is created
        
        block.RegBlockMethod('CheckParameters', @CheckPrms); % called during update diagram
        % block.RegBlockMethod('Start', @Start); % called first
        block.RegBlockMethod('PostPropagationSetup', @PostPropSetup); 
        block.RegBlockMethod('InitializeConditions', @InitConditions); % called second
        block.RegBlockMethod('Outputs', @Output); % called first in sim loop
        % block.RegBlockMethod('Update', @Update); % called second in sim loop
        block.RegBlockMethod('Terminate', @Terminate);
    end

%%
    function CheckPrms(block)        
        try
            validateattributes(block.DialogPrm(1).Data, {'char'}, {'nonempty'});  % Name of arduino instance
            validateattributes(block.DialogPrm(2).Data, {'numeric'}, {'real', 'scalar', 'nonnegative'}); % pin
            errstr=arduino.checknum(block.DialogPrm(2).Data,'pin number',2:69);
            if ~isempty(errstr), disp(errstr); error(errstr); end
            validateattributes(block.DialogPrm(3).Data, {'numeric'}, {'real', 'scalar', 'nonzero'}); % sample time
        catch %#ok<CTCH>
            error('Simulink:ArduinoIO:invalidParameter', 'Invalid value for a mask parameter');
        end
    end

%%
    function PostPropSetup(block)
        st = block.SampleTimes;
        if st(1) == 0
            error('The ArduinoIO library blocks can only handle discrete sample times');
        end        
    end

%%
    function InitConditions(block) 
        % fprintf('%s: InitConditions\n', getfullname(block.BlockHandle));        
        customData = getSetupBlockUserData(bdroot(block.BlockHandle), block.DialogPrm(1).Data);
        myArduino = customData('arduinoHandle');
        %myPin = block.DialogPrm(2).Data;
        %myArduino.pinMode(myPin, 'input');
        
    end

%%
    function Output(block)
        % fprintf('%s: Output\n', getfullname(block.BlockHandle));
        duration = myArduino.Ultrasound();
        
      
        if isempty(duration )
            duration  = 0;
        end        
        block.OutputPort(1).Data = duration ;
    end

%%
    function Terminate(block) %#ok<INUSD>
         % The ArduinoIO Setup block handles cleanup of myArduino
    end

end

You can see the result in the attachment. I get correct measurements however to get the distance measurement for 1.6 seconds I need to wait 10-15 seconds. So it's not real time anymore. There is a huge delay. What is your opinion about this delay?

Perhaps the fine folks at http://snippets-r-us.com could help you with your snippets.

Have you tried an Arduino program that works without Matlab Simulink? That will enable you to see if this is an Arduino problem or a Matlab problem.

...R

Robin2:
Have you tried an Arduino program that works without Matlab Simulink? That will enable you to see if this is an Arduino problem or a Matlab problem.

...R

Well, I checked the ultrasonic sensor via just coding from IDE there is no problem on the Arduino side.

Also, I achieved lighting a led with the same procedure. And there wasn't any delay. I believe this is a serial communication problem. Not sure.

MuharremAkkaya:
Well, I checked the ultrasonic sensor via just coding from IDE there is no problem on the Arduino side.

Also, I achieved lighting a led with the same procedure. And there wasn't any delay. I believe this is a serial communication problem. Not sure.

That all suggests that the problem is on the Matlab side so maybe it would be more productive to ask on a Matlab Forum.

...R

Robin2:
That all suggests that the problem is on the Matlab side so maybe it would be more productive to ask on a Matlab Forum.

...R

Thanks for the help.

For the one who wants to follow the topic on Mathworks: