www.gusucode.com > ros 工具箱 matlab源码程序 > ros/+robotics/+ros/+internal/Global.m

    classdef Global
    %This class is for internal use only. It may be removed in the future.
    
    %GLOBAL Functions for handling the global node and global core
    %   MATLAB uses a unique, global ROS node object for each running MATLAB
    %   session. Optionally, MATLAB can also launch a global core.
    %   The robotics.ros.internal.Global class exposes functions that allow the
    %   manipulation of these global entities.
    %
    %   robotics.ros.internal.Global methods:
    %      core  - Initialize or clear the global ROS core object
    %      node  - Initialize or clear the global ROS node object
    
    %   Copyright 2014-2015 The MathWorks, Inc.
    
    properties(Access = ?matlab.unittest.TestCase, Constant)
        %DefaultCorePort - The default port to start the global core       
        DefaultCorePort = 11311
        
        %DefaultNodeName - The default prefix for the global node name
        DefaultNodeName = 'matlab_global_node_'
        
        %DefaultNodeNameDigits - Number of digits that are suffixed to the global node name
        DefaultNodeNameDigits = 5
        
        %RandomSource - Source of pseudo-random numbers for node name
        RandomSource = robotics.internal.Random
    end
    
    methods (Static)
        function masterURI = core( op, port )
            %CORE Initialize or clear the global core object  
            %   The operation 'op' defines the behavior of this function.
            %
            %   robotics.ros.internal.Global.core('clear') clears (deletes) the global
            %   core. It will be reinitialized on the next call to ROSINIT or
            %   robotics.ros.internal.Global.core('init')
            %
            %   robotics.ros.internal.Global.core('init', PORT)
            %   initializes the global ROS core on PORT. This call will fail
            %   if there is another core already running on that port. If
            %   PORT is [], the default of 11311 will be used.

            switch op
                case 'clear'
                    robotics.ros.internal.Global.coreInstance('clear');
                    if nargout > 0
                        masterURI = [];
                    end
                case 'init'
                    if isempty(port)
                        port = robotics.ros.internal.Global.DefaultCorePort;
                    end
                    
                    core = robotics.ros.internal.Global.coreInstance('init', ...
                        port);
                    
                    if nargout > 0
                        masterURI = core.MasterURI;
                    end
                    
                otherwise
                    error(message('robotics:ros:core:GlobalCoreInvalidOp', op));                    
            end
        end
        
        function node( op, name, masterURI, nodeHost )
            %NODE Initialize or clear the global node object
            %   The operation 'op' defines the behavior of this function.
            %
            %   robotics.ros.internal.Global.node('clear') clears (deletes) the global
            %   node. It will be reinitialized on the next call to ROSINIT or
            %   robotics.ros.internal.Global.node('init')
            %
            %   robotics.ros.internal.Global.node('init', 'NAME', 'MASTERURI', 'NODEHOST')
            %   initializes the global ROS node. 
            %   NAME is a the node name (specify '' if 
            %   the default should be used). MASTERURI denotes the Master
            %   URI that the global node should connect to (use '' if the
            %   default should be used). The NODEHOST setting is used by
            %   the node to advertise itself (use '' for default).

            switch op
                case 'clear'
                    robotics.ros.internal.Global.nodeInstance('clear');
                    
                case 'init'
                    % Always clear existing node
                    robotics.ros.internal.Global.nodeInstance('clear');
                    
                    % Then re-initialize node
                    robotics.ros.internal.Global.nodeInstance('init', ...
                        name, masterURI, nodeHost);
                    
                otherwise
                    error(message('robotics:ros:node:GlobalNodeInvalidOp', op));
            end                                     
        end
        
        function [active, nodeHandle] = isNodeActive
            %isNodeActive Check if global node is running or not.
           
            try
                nodeHandle = robotics.ros.internal.Global.getNodeHandle(false);
                active = true;
            catch
                active = false;
                nodeHandle = [];
            end
        end
        
        function [active, coreHandle] = isCoreActive
            %isCoreActive Check if global core is running or not.
           
            try
                coreHandle = robotics.ros.internal.Global.getCoreHandle(false);
                active = true;
            catch
                active = false;
                coreHandle = [];
            end
        end
        
        function node = getNodeHandle(init)
            %getNodeHandle Get instance of the global node
                
            node = robotics.ros.internal.Global.nodeInstance;
            if ~isempty(node)
                return;
            end
                 
            % The global node is not initialized
            if init
                % Initialize the node if requested by the caller
                robotics.ros.internal.Global.node('init', '', '', '');
                node = robotics.ros.internal.Global.nodeInstance;
            else
                % If user did not request a node start, throw an
                % appropriate error message
                error(message('robotics:ros:node:GlobalNodeNotRunning'));
            end            
        end
        
        function core = getCoreHandle(init)
            %getCoreHandle Get instance of the global node
            
            core = robotics.ros.internal.Global.coreInstance;
            if ~isempty(core)
                return;
            end
            
            % The global core is not initialized            
            if init
                % Initialize the core if requested by the caller
                robotics.ros.internal.Global.core('init', []);
                core = robotics.ros.internal.Global.coreInstance;
            else
                % If user did not request a core start, throw an
                % appropriate error message
                error(message('robotics:ros:core:GlobalCoreNotRunning'));                
            end
        end        
    end
    
    
    methods(Access = private, Static)
        function n = nodeInstance(op, name, masterURI, nodeHost)
            persistent node
            mlock
            
            if nargin == 0
                n = node;
                return;
            end
            
            switch op
                case 'clear'
                    clearNode;
                case 'init'
                    initNode(name, masterURI, nodeHost);
            end
            
            function initNode(name, masterURI, nodeHost)
                if isempty(name)
                    name = robotics.ros.internal.Global.DefaultNodeName;
                    nodeCreateFcn = @(n,uri,nhost)robotics.ros.internal.Global.createNodeWithDefaultName(n, uri, 'NodeHost', nhost);
                else
                    nodeCreateFcn = @(n,uri,nhost)robotics.ros.Node(n, uri, 'NodeHost', nhost);
                end
                
                clearNode;
                node = nodeCreateFcn(name, masterURI, nodeHost);
                disp(getString(message('robotics:ros:node:InitializeGlobal', ...
                    node.Name, node.NodeURI)));
            end
            
            function clearNode
                % Check for the unlikely case that node is already a
                % deleted handle and recover gracefully.
                if isobject(node) && ~isvalid(node)
                    node = [];
                    return;
                end
                
                if ~isempty(node)
                    disp(getString(message('robotics:ros:node:ShuttingDownGlobal', ...
                        node.Name, node.NodeURI)));
                    delete(node);
                    node = [];
                end                
            end
            
        end
        
        function c = coreInstance(op, port)
            persistent core
            mlock

            if nargin == 0
                c = core;
                return;
            end            
            
            switch op
                case 'init'
                    initCore(port);
                    c = core;
                    
                case 'clear'
                    clearCore();
                    return;
            end
            
            function clearCore
                % Check for the unlikely case that core is already a
                % deleted handle and recover gracefully.
                if isobject(core) && ~isvalid(core)
                    core = [];
                    return;
                end
                
                if ~isempty(core)
                    disp(getString(message('robotics:ros:core:ShuttingDownGlobal', ...
                        core.MasterURI)));
                    delete(core);
                    core = [];
                end
            end
            
            function initCore(port)
                if isempty(core)
                    core = robotics.ros.Core(port);
                    disp(getString(message('robotics:ros:core:InitializeGlobal', ...
                        core.MasterURI)));
                    return;
                end
                
                % If port number is different, restart core
                if port ~= core.Port
                    clearCore();
                    core = robotics.ros.Core(port);
                    disp(getString(message('robotics:ros:core:InitializeGlobal', ...
                        core.MasterURI)));
                end
            end
        end        
        
        function node = createNodeWithDefaultName(name, varargin)
            %createNodeWithDefaultName Create the global ROS node with a default name
            %   The input arguments are fed straight into the robotics.ros.Node constructor.
            
            nodeCreated = false;
            
            % Create random node name
            % Cycle multiple times in the (very unlikely) case that a node with 
            % the same name already exists.
            retryMax = 3;
            retryCount = 0;
            
            numDigits = robotics.ros.internal.Global.DefaultNodeNameDigits;
            
            while ~nodeCreated
                % Use a random number as a suffix
                randNumStr = robotics.ros.internal.Global.RandomSource.timeNumericString(numDigits);
                try
                    node = robotics.ros.Node([name randNumStr], varargin{:});
                catch ex
                    switch ex.identifier
                        case 'robotics:ros:node:NodeNameExists'
                            % This exception occurred because our
                            % random name collides with a name of a
                            % different node. Retry the node creation with
                            % a different random name up to retryMax times.
                            if retryCount == retryMax
                                error(message('robotics:ros:node:DefaultNodeNameError'));
                            end
                            retryCount = retryCount + 1;
                            
                            % Pause for a little bit to ensure that time is
                            % changing. Randomize the wait time between 0.05 and 0.15
                            % seconds, in case that multiple instances of MATLAB 
                            % use the same time base.
                            waitTime = 0.1 + 0.1*(rand-0.5);
                            pause(waitTime);
                            continue;
                        otherwise
                            % Some other exception occurred.
                            rethrow(ex);
                    end
                end
                nodeCreated = true;
            end
        end
    end
    
end