Incorrect Data Interpretation in UDP Reception with Simulink

On an ESP32, I am sending distance data via UDP to MATLAB. There are multiple distances involved, so both the receiver number (from 1 to 4) and the respective distance are transmitted. I can also receive and analyze the data using the following program:
% Set up the UDP receiver
udpReceiver = udpport("LocalPort", 4141);
% Define a function to parse the received UDP packet
% Main loop to continuously receive and display distances
while true
% Check if a packet is available
if udpReceiver.NumBytesAvailable > 0
% Read the packet
packet = read(udpReceiver, udpReceiver.NumBytesAvailable, "char");
% Parse the received packet
[distance1, distance2, distance3, distance4] = parsePacket(packet);
% Display current distances
fprintf('Distance from Device 1: %.2f meters\n', distance1);
fprintf('Distance from Device 2: %.2f meters\n', distance2);
fprintf('Distance from Device 3: %.2f meters\n', distance3);
fprintf('Distance from Device 4: %.2f meters\n', distance4);
fprintf('\n'); % Add newline for clarity
end
pause(0.1);
end
% Clean up
delete(udpReceiver)
function [distance1, distance2, distance3, distance4] = parsePacket(packet)
% Convert packet to string
packetStr = char(packet);
% Split the string by semicolon
data = strsplit(packetStr, ';');
% Initialize distances
distance1 = NaN;
distance2 = NaN;
distance3 = NaN;
distance4 = NaN;
% Parse each part of the data
for i = 1:length(data)
% Split by comma to separate address and distance
parts = strsplit(data{i}, ',');
device = str2double(parts{1});
distance = str2double(parts{2});
% Assign distances based on address
switch device
case 1
distance1 = distance;
case 2
distance2 = distance;
case 3
distance3 = distance;
case 4
distance4 = distance;
end
end
end
Now I want to further process only the respective distances in Simulink. For this, I have converted the code into a Level 2 MATLAB function. Here is the code for it:
function UDP_Receiver(block)
setup(block);
function setup(block)
block.NumInputPorts = 0;
block.NumOutputPorts = 4;
block.SetPreCompInpPortInfoToDynamic;
block.SetPreCompOutPortInfoToDynamic;
block.NumDialogPrms = 0;
block.SampleTimes = [-1 0];
block.SimStateCompliance = 'DefaultSimState';
block.RegBlockMethod('SetInputPortSamplingMode', @SetInpPortFrameData);
block.RegBlockMethod('Outputs', @Outputs);
block.RegBlockMethod('Terminate', @Terminate);
% Initialize UDP receiver
% Set output port sampling modes
for i = 1:block.NumOutputPorts
block.OutputPort(i).SamplingMode = 'Sample'; % Set all output ports to Sample mode
end
block.SetAccelRunOnTLC(true);
function SetInpPortFrameData(block, idx, fd)
block.InputPort(idx).SamplingMode = fd;
for i = 1:block.NumOutputPorts
block.OutputPort(i).SamplingMode = fd;
end
function Outputs(block)
udpreceiver = udpport("LocalPort", 4141);
% Check if UDP receiver is valid
while true
if isvalid(udpreceiver)
% Check if a packet is available
if udpreceiver.NumBytesAvailable > 0
% Read the packet
packet = read(udpreceiver, udpreceiver.NumBytesAvailable, "char");
% Parse the received packet
[distance1, distance2, distance3, distance4] = parsePacket(packet);
% Output distances
block.OutputPort(1).Data = distance1;
block.OutputPort(2).Data = distance2;
block.OutputPort(3).Data = distance3;
block.OutputPort(4).Data = distance4;
end
end
end
function Terminate(block)
% Define a function to parse the received UDP packet
function [distance1, distance2, distance3, distance4] = parsePacket(packet)
% Initialize distances
distance1 = NaN;
distance2 = NaN;
distance3 = NaN;
distance4 = NaN;
% Convert packet to string
packetStr = char(packet);
% Split the string by semicolon
data = strsplit(packetStr, ';');
% Parse each part of the data
for i = 1:length(data)
% Split by comma to separate address and distance
parts = strsplit(data{i}, ',');
if numel(parts) == 2
device = str2double(parts{1});
distance = str2double(parts{2});
% Assign distances based on address
switch device
case 1
distance1 = distance;
case 2
distance2 = distance;
case 3
distance3 = distance;
case 4
distance4 = distance;
end
end
end
Even though it is the same code, the simulation gets terminated or the Data is wrong. What can i do?

Answers (1)

Hi @David,

After reading your comments, this is what I have comprehended so far, you are implementing a UDP communication system between an ESP32 microcontroller and MATLAB, where multiple distance measurements are sent and received and successfully set up a MATLAB script to receive these distances and display them. Now, you are attempting to adapt this code for use in Simulink as a Level 2 MATLAB function but are encountering issues with incorrect data or premature termination of the simulation. Now, after analyzing your code, I found following issues, in the outputs function, the UDP receiver is being initialized inside the function, which can lead to repeated initialization and potential resource conflicts. Your while true loop in Outputs May cause Simulink to hang or terminate if not managed correctly, as it blocks further execution unless conditions are met. Also, there might be issues in how data is being parsed or updated in the output ports, especially if packets arrive at varying times. I would suggest following modifications to implement in your code.

Initialize UDP Receiver once by moving the UDP port initialization outside of the Outputs function to avoid reinitializing it on every call which can be done in the setup function:

function setup(block)
         block.UserData.udpReceiver = udpport("LocalPort", 4141);
end

Then, access this receiver in your Outputs function:

     function Outputs(block)
       udpreceiver = block.UserData.udpReceiver;
     end

Secondly, manage your infinite loop, instead of using an infinite loop within Outputs utilize Simulink’s built-in mechanisms for sample time and event-driven processing. You can use a periodic sample time that checks for available bytes:

   function Outputs(block)
       udpreceiver = block.UserData.udpReceiver;
       if isvalid(udpreceiver) && udpreceiver.NumBytesAvailable > 0
           packet = read(udpreceiver, udpreceiver.NumBytesAvailable, "char");
           [distance1, distance2, distance3, distance4] = parsePacket(packet);
           block.OutputPort(1).Data = distance1;
           block.OutputPort(2).Data = distance2;
           block.OutputPort(3).Data = distance3;
           block.OutputPort(4).Data = distance4;
       else
           % Handle no data case
           block.OutputPort(1).Data = NaN;
           block.OutputPort(2).Data = NaN;
           block.OutputPort(3).Data = NaN;
           block.OutputPort(4).Data = NaN;
       end
   end
   In the Terminate function, clean up resources by deleting the UDP receiver:
     function Terminate(block)
       udpreceiver = block.UserData.udpReceiver;
       if isvalid(udpreceiver)
           delete(udpreceiver);
       end
   end

If you still encounter issues with incorrect data, add debugging statements within your `parsePacket` function to log received packets and parsed values:

   fprintf('Received packet: %s\n', packetStr);

Hope, for now, this helps. Please let me know if you have any further questions.

Products

Release

R2022a

Asked:

on 17 Jul 2024

Answered:

on 15 Aug 2024

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!