How to store object(like udp object) in level-2 s-function?

86 次查看(过去 30 天)
Hello all,
I want to send control input from Matlab to FlightGear and receive aircraft data from FlightGear to Matlab with UDP communication.
So I made a code below:
function FG_Simulink(block)
% Level-2 MATLAB file S-Function for UDP communication with FlightGear
setup(block)
function setup(block)
% Register number of dialog parameters
block.NumDialogPrms = 0; % UDP send and receive ports
% Register number of input and output ports
block.NumInputPorts = 4; % aileron, elevator, rudder, throttle
block.NumOutputPorts = 11; % u, v, w, alpha, beta, p, q, r, phi, theta, psi
% Setup functional port dimensions
block.SetPreCompInpPortInfoToDynamic;
block.SetPreCompOutPortInfoToDynamic;
% Register sample times
% Specify discrete sample time with a period of 0.01 seconds and an offset of 0
block.SampleTimes = [0, 0]; % Correct format for discrete sample time
% Specify the block simStateCompliance.
block.SimStateCompliance = 'DefaultSimState';
% Register methods
block.RegBlockMethod('Start', @Start);
block.RegBlockMethod('Outputs', @Outputs);
block.RegBlockMethod('Terminate', @Terminate);
block.RegBlockMethod('SetInputPortSamplingMode', @SetInputPortSamplingMode);
block.RegBlockMethod('PostPropagationSetup', @DoPostPropSetup);
function SetInputPortSamplingMode(block, port, mode)
% Set the input port sampling mode
block.InputPort(port).SamplingMode = mode;
% Set the same sampling mode for all output ports
for i = 1:block.NumOutputPorts
block.OutputPort(i).SamplingMode = mode;
end
function DoPostPropSetup(block)
% Setup Dwork
block.NumDworks = 0;
% Setup Pwork (Pointer Work Vector) for storing UDP object
block.NumPworks = 2; % We need to store two UDP objects
function Start(block)
% Declare persistent variables to store UDP sender and receiver
persistent UdpSender UdpReceiver
% Initialize UDP sender and receiver
% Retrieve ports from dialog parameters
if isempty(UdpSender)
try
UdpSender = udpport("IPV4",'LocalPort',55001, 'Timeout', 1);
block.Pwork(1).Data = UdpSender;
catch e
error('Failed to bind sender UDP port: %s', e.message);
end
end
if isempty(UdpReceiver)
try
UdpReceiver = udpport("IPV4",'LocalPort',55002, 'Timeout', 1);
block.Pwork(2).Data = UdpReceiver;
catch e
error('Failed to bind receiver UDP port: %s', e.message);
end
end
function Outputs(block)
% Retrieve UDP objects from UserData
% Create input data vector
inputVector = zeros(1, 4);
inputVector(1) = block.InputPort(1).Data; % aileron
inputVector(2) = block.InputPort(2).Data; % elevator
inputVector(3) = block.InputPort(3).Data; % rudder
inputVector(4) = block.InputPort(4).Data; % throttle
Udpsender = block.Pwork(1).Data;
Udpreceiver = block.Pwork(2).Data;
% Send input data to FlightGear
try
write(Udpsender, inputVector, 'double', "LocalPort",55002); % Send to FlightGear receive port
catch e
warning('Failed to send data to FlightGear: %s', '%s', e.message);
end
% Receive flight data from FlightGear
try
data = read(Udpreceiver, 88, "double"); % 11 floats * 4 bytes each
if ~isempty(data)
outputVector = typecast(data, 'double');
for i = 1:block.NumOutputPorts
block.OutputPort(i).Data = outputVector(i);
end
end
catch e
% Handle timeout or any read errors
warning('Failed to receive data from FlightGear: %s', '%s', e.message);
end
function Terminate(block)
But when I launch a simulink file, the error was occured : "Cause: The property 'NumPworks' is not recognized for the class 'Simulink.MSFcnRunTimeBlock'."
I know that Dwork can not store the object type data, so if you have any idea to solve this problem, please let me know.
Thank you.

回答(1 个)

Divyam
Divyam 2024-8-21,4:21
To store the UDP packets associated with a specific Simulink block, the "UserData" parameter of the Simulink block can be utilized to store data across callbacks. For your reference, I have made the edits to the "Start" function which incorporates the desired functionality.
function Start(block)
% Declare persistent variables to store UDP sender and receiver
persistent UdpSender UdpReceiver
%-- Get the block path --%
blockPath = gcb(block);
%-- Comment the below line if you don't wish to store the UserData persistently --%
set_param(gcb, 'UserDataPersistent', 'on');
% Initialize UDP sender and receiver
% Retrieve ports from dialog parameters
if isempty(UdpSender)
try
UdpSender = udpport("IPV4",'LocalPort',55001, 'Timeout', 1);
%-- Setting the UserData property to store UDP object --%
set_param(blockPath, 'UserData', UdpSender);
catch e
error('Failed to bind sender UDP port: %s', e.message);
end
end
if isempty(UdpReceiver)
try
UdpReceiver = udpport("IPV4",'LocalPort',55002, 'Timeout', 1);
%-- Setting the UserData property to store UDP object --%
set_param(blockPath, 'UserData', UdpReceiver);
catch e
error('Failed to bind receiver UDP port: %s', e.message);
end
end
For more information regarding the 'UserData' parameter, you can refer to this documentation: https://www.mathworks.com/help/simulink/ug/associating-user-data-with-blocks.html
  2 个评论
준호
준호 2024-8-26,6:56
Hi Divyam,
I followed your advice, but the following issues have occurred:
  1. In the line blockPath = gcb(block);, an error message saying 'Invalid Simulink object handle.' appears. However, if I remove the block parameter from gcb, it works.
  2. In the Output method, when I call get_param to obtain the udpport object, I get a warning message stating, 'Loading udpport objects from a MAT-file is not supported.'
Here is a code.
function Start(block)
% Declare persistent variables to store UDP sender and receiver
persistent UdpSender UdpReceiver
% Initialize UDP sender and receiver
% Get the block path
blockPath = gcb();
% Comment the below line if you don't wish to store the UserData persistently
set_param(blockPath, 'UserDataPersistent', 'on');
if isempty(UdpSender)
try
UdpSender = udpport("IPV4",LocalHost="127.0.0.1",LocalPort=55002);
catch e
error('Failed to bind sender UDP port: %s', e.message);
end
end
if isempty(UdpReceiver)
try
UdpReceiver = udpport("IPV4",LocalHost="127.0.0.1",LocalPort=55001);
catch e
error('Failed to bind receiver UDP port: %s', e.message);
end
end
% Check the information about udp objects
disp(UdpSender);
disp(UdpReceiver);
try
% Setting the UserData property to store UDP object
Objects = [UdpSender, UdpReceiver];
set_param(blockPath, 'UserData', Objects);
catch e
error('Failed to store UDP objects: %s', e.message);
end
function Outputs(block)
% Retrieve UDP objects from UserData
% Create input data vector
inputVector = zeros(1, 4);
inputVector(1) = block.InputPort(1).Data; % aileron
inputVector(2) = block.InputPort(2).Data; % elevator
inputVector(3) = block.InputPort(3).Data; % rudder
inputVector(4) = block.InputPort(4).Data; % throttle
% Get the persistant UDP object
try
[Sender, Receiver] = get_param(gcb, 'UserData');
catch e
warning('Failed to get object: %s', '%s', e.message);
end
% Send input data to FlightGear
try
write(Sender, inputVector, 'double', "LocalPort",55002); % Send to FlightGear receive port
catch e
warning('Failed to send data to FlightGear: %s', '%s', e.message);
end
% Receive flight data from FlightGear
try
data = read(Receiver, 88, "double"); % 11 floats * 4 bytes each
if ~isempty(data)
outputVector = typecast(data, 'double');
for i = 1:block.NumOutputPorts
block.OutputPort(i).Data = outputVector(i);
end
end
catch e
% Handle timeout or any read errors
warning('Failed to receive data from FlightGear: %s', '%s', e.message);
end
How can I troubleshoot it?
Divyam
Divyam 2024-8-26,8:57
Hi @준호, to use the 'gcb' command effectively in order to get the path of the block, you first need to select the block for which you are performing the operation. In your use case it would indeed make sense to omit the 'block' parameter from the 'gcb' command.
As an alternative, remove the 'gcb' command from your code and add 'blockPath' as a function input parameter itself, that should resolve your error.
To avoid writing data to the MAT file you can write data to the UDP port itself via this method.
u1 = udpport;
% Writing the data to the UDP socket itself
write(u1,<data>,<destination address>,<destination port>)
% Reading the data from a UDP socket
dataRead = read(u1,u1.NumBytesAvailable,'uint8')

请先登录,再进行评论。

Community Treasure Hunt

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

Start Hunting!

Translated by