How to store object(like udp object) in level-2 s-function?
7 views (last 30 days)
Show older comments
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.
0 Comments
Answers (1)
Divyam
on 21 Aug 2024
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 Comments
Divyam
on 26 Aug 2024
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')
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!