www.gusucode.com > robotsimulink 工具箱 matlab源码程序 > robotsimulink/robotslros/+robotics/+slros/+internal/+block/Publisher.m
classdef Publisher < matlab.System %This class is for internal use only. It may be removed in the future. %Publish messages to a ROS network % % H = robotics.slros.internal.block.Publisher creates a system % object, H, that advertises a topic to a ROS network and publishes % messages to that topic. % % This system object is intended for use with the MATLAB System % block. In order to access the ROS functionality from MATLAB, see % ROSPUBLISHER. % % See also robotics.slros.internal.block.Subscriber % Copyright 2014-2016 The MathWorks, Inc. %#codegen properties (Nontunable) %ROSTopic Topic to publish to % This sytem object will use ROSTopic as specified in both % simulation and code generation. In particular, it will not add a % "/" in front of topic, as that forces the topic to be in the % absolute namespace. ROSTopic = '/my_topic' %ROSMessageType Message type of topic % e.g., 'std_msgs/Int32' ROSMessageType = 'std_msgs/Int32' %MessageQueueLen Length of publish queue % Only used in generated code MessageQueueLen = 1 end % The following should ideally not show up in the MATLAB System block % dialog. However, setting them as 'Hidden' will prevent them from % being accessible via set_param & get_param. properties(Nontunable) %SLBusName Simulink Bus Name for message type % Not really used; only maintained for symmetry with Subscriber SLBusName = '' %ModelName Name of Simulink model % Used for managing node instance ModelName = 'untitled' %BlockId Simulink Block Identifier % Used to generate unique identifier for the block during code % generation. This should be obtained using Simulink.ID.getSID() % on the library block (*not* the MATLAB system block). The % SID has the format '<modelName>:<blocknum>' BlockId = 'pub1' %OutputStreamWsVar Output message to variable in base worksace % Used to redirect Publisher to send messages to a workspace % variable instead of to ROS network (used for testing only). % The workspace variable should be created like this: % % workspaceVar = robotics.slros.internal.sim.MsgListOutputStream(rostopic, msgtype); % % After simulation, workspaceVar.MessageList has the list of % messages that have been sent to MsgListOutputStream object. % This capability of using workspace variables is only used in % internal testing, and is not documented for Simulink users. OutputStreamWsVar = '' end properties(Constant,Access=private) % Name of header file with declarations for variables and types % referred to in code emitted by setupImpl and stepImpl. HeaderFile = robotics.slros.internal.cgen.Constants.InitCode.HeaderFile end properties (Access=private, Transient) % Converter - Handle to object that encapsulats converting a % Simulink bus struct to a MATLAB ROS message. It is initialized to % indicate the class of the object Converter = robotics.slros.internal.sim.BusStructToROSMsgConverter.empty % OutputStream - Handle to object that implements robotics.slros.internal.sim.MsgOutputStream % This can be a sim.MsgNetOutputStream (for sending messages to % the ROS network) or sim.MsgListOutputStream (for sending messages % to an object in the base workspace (used in conjunction with % OutputStreamWsVar property) OutputStream % ROSMaster - Handle to an object that encapsulates interaction % with the ROS master. It is initialized to indicate the class of % the object. ROSMaster = robotics.slros.internal.sim.ROSMaster.empty end methods function obj = Publisher(varargin) % Enable code to be generated even this file is p-coded coder.allowpcode('plain'); % Support name-value pair arguments when constructing the object. setProperties(obj,nargin,varargin{:}); end function set.ROSTopic(obj, val) validateattributes(val, {'char'}, {'nonempty'}, '', 'ROSTopic'); if coder.target('MATLAB') robotics.ros.internal.Namespace.canonicalizeName(val); % throws error end obj.ROSTopic = val; end function set.ROSMessageType(obj, val) validateattributes(val, {'char'}, {'nonempty'}, '', 'ROSMessageType'); if coder.target('MATLAB') robotics.ros.internal.Namespace.canonicalizeName(val); % throws error end obj.ROSMessageType = val; end function set.MessageQueueLen(obj, val) validateattributes(val, ... {'numeric'}, {'positive', 'integer', 'scalar'}, '', 'MessageQueueLen'); obj.MessageQueueLen = int32(val); end function set.SLBusName(obj, val) validateattributes(val, {'char'}, {}, '', 'SLBusName'); obj.SLBusName = val; end function set.ModelName(obj, val) validateattributes(val, {'char'}, {'nonempty'}, '', 'ModelName'); obj.ModelName = val; end function set.BlockId(obj, val) validateattributes(val, {'char'}, {'nonempty'}, '', 'BlockId'); obj.BlockId = val; end function set.OutputStreamWsVar(obj, val) validateattributes(val, {'char'}, {}, '', 'OutputStreamWsVar'); obj.OutputStreamWsVar = val; end end methods (Access = protected) function num = getNumInputsImpl(~) num = 1; end function num = getNumOutputsImpl(~) num = 0; end end methods (Access = protected) %% Common functions function out = constantSampleTimePropagationImpl(~) % Enable this system object to inherit constant ('inf') sample times out = 'Allow'; end % We don't save SimState, since there is no way save & restore % the Publisher object. However, saveObjectImpl and loadObjectImpl % are required since we have private properties. function s = saveObjectImpl(obj) % The errorIf() below will ensure that FastRestart cannot be used % in a model with ROS blocks coder.internal.errorIf(true, 'robotics:robotslros:sysobj:PublisherSimStateNotSupported'); s = saveObjectImpl@matlab.System(obj); end function loadObjectImpl(obj,s,wasLocked) loadObjectImpl@matlab.System(obj,s,wasLocked); end function setupImpl(obj, ~) % setupImpl is called when model is being initialized at the % start of a simulation if coder.target('MATLAB') % Executing in MATLAB interpreted mode modelHasPriorState = robotics.slros.internal.sim.ModelStateManager.hasState(obj.ModelName); nodeRefCountIncremented = false; try %#ok<EMTC> modelState = robotics.slros.internal.sim.ModelStateManager.getState(obj.ModelName, 'create'); % The following could be a separate method, but system % object infrastructure doesn't appear to allow it %-- if ~isempty(obj.OutputStreamWsVar) % Use a variable in MATLAB Workspace as the recipient of messages. obj.OutputStream = evalin('base', obj.OutputStreamWsVar); validateattributes(obj.OutputStream, {'robotics.slros.internal.sim.MsgListOutputStream'}, {'scalar'}); else % Use ROS network as a recipient of messages. if isempty(modelState.ROSNode) || ~isvalid(modelState.ROSNode) obj.ROSMaster = robotics.slros.internal.sim.ROSMaster(); % verifyReachable() errors if ROS master is unreachable obj.ROSMaster.verifyReachable(); % createNode() errors if unable to create node % (e.g., if node with same name already exists) uniqueName = obj.ROSMaster.makeUniqueName(obj.ModelName); modelState.ROSNode = obj.ROSMaster.createNode(uniqueName); end obj.OutputStream = robotics.slros.internal.sim.MsgNetOutputStream(... obj.ROSTopic, obj.ROSMessageType, modelState.ROSNode); end %-- modelState.incrNodeRefCount(); nodeRefCountIncremented = true; obj.Converter = robotics.slros.internal.sim.BusStructToROSMsgConverter(... obj.ROSMessageType, obj.ModelName); catch ME if nodeRefCountIncremented modelState.decrNodeRefCount(); end obj.OutputStream = []; if ~modelHasPriorState || ~modelState.nodeHasReferrers() robotics.slros.internal.sim.ModelStateManager.clearState(obj.ModelName); end % RETHROW will generate a hard-to-read stack trace, so % use THROW instead. throw(ME); end elseif coder.target('RtwForRapid') % Rapid Accelerator. In this mode, coder.target('Rtw') % returns true as well, so it is important to check for % 'RtwForRapid' before checking for 'Rtw' coder.internal.errorIf(true, 'robotics:robotslros:sysobj:PublisherRapidAccelNotSupported'); elseif coder.target('Rtw') coder.cinclude(obj.HeaderFile); % Append 0 to obj.ROSTopic, since MATLAB doesn't % automatically zero-terminate strings in generated code zeroDelimTopic = [obj.ROSTopic 0]; coder.ceval([obj.BlockId '.createPublisher'], ... zeroDelimTopic, int32(obj.MessageQueueLen)); elseif coder.target('Sfun') % 'Sfun' - SimThruCodeGen target % Do nothing. MATLAB System block first does a pre-codegen % compile with 'Sfun' target, & then does the "proper" % codegen compile with Rtw or RtwForRapid, as appropriate. else % 'RtwForSim' - ModelReference SIM target % 'MEX', 'HDL', 'Custom' - Not applicable to MATLAB System block coder.internal.errorIf(true, 'robotics:robotslros:sysobj:UnsupportedCodegenMode'); end end function stepImpl(obj,busstruct) % Buses are treated as structures if coder.target('MATLAB') % executing in MATLAB rosmsg = obj.Converter.convert(busstruct); obj.OutputStream.sendMessage(rosmsg); elseif coder.target('Rtw') % The datatype of msg will be derived from the input to the block coder.ceval([obj.BlockId '.publish'], coder.rref(busstruct)); end end %% function releaseImpl(obj) if coder.target('MATLAB') % We need to release all the OutputStreams (which hold the % publisher) before releasing the node. If the order is % reversed, the Publisher tries to connect to the master % to unregister & waits for this operation to succeed (w/ a % time out), which causes a delay during model termination. st = robotics.slros.internal.sim.ModelStateManager.getState(obj.ModelName); st.decrNodeRefCount(); obj.OutputStream = []; % release publisher if ~st.nodeHasReferrers() robotics.slros.internal.sim.ModelStateManager.clearState(obj.ModelName); end else % coder.target('Rtw') % Nothing to do. The system object will never be released % in the generated node. end end end end