www.gusucode.com > Arduino_Engineering_Kit_Hardware_Support_18b 工具箱matlab源码程序 > Arduino_Engineering_Kit_Hardware_Support_18b/matlab/MATLABAddon/+arduinoioaddons/+arduino/MKRDCMotor.m

    classdef MKRDCMotor < arduinoio.MotorBase & matlab.mixin.CustomDisplay
    %MKRDCMotor Create a MKR DC motor device object.
    
    % Copyright 2018 The MathWorks, Inc.
    
    properties
        DutyCycle = 0
    end
    
    properties(Hidden)
        PWMFrequency = 100
    end
    
    properties (Dependent = true, Access = private)
        ConvertedDutyCycle
    end
    
    properties (SetAccess = private)
        IsRunning = false;
    end
    
    properties(Access = private)
        ResourceOwner = 'MKRMotorCarrier\DCMotor';
        MinPWMFrequency = 100
        MaxPWMFrequency = 10000
    end
    
    properties(Access = private, Constant = true)
        % MATLAB defined command IDs
        CREATE_DC_MOTOR     = hex2dec('02')
        START_DC_MOTOR      = hex2dec('03')
        STOP_DC_MOTOR       = hex2dec('04')
        SET_DUTYCYCLE_DC_MOTOR  = hex2dec('05')
        SET_DCM_VELOCITY    = hex2dec('13')
        SET_DCM_POSITION    = hex2dec('14')
    end
    
    properties(Access = private, Constant = true)
        ROTATE_FORWARD  = 1
        ROTATE_BACKWARD = 2
    end
    
    properties(Access = private, Constant = true)
        MaxDCMotors = 4
        ResourceMode = 'MKRMotorCarrier\DCMotor';
    end
    
    %% Constructor
    methods(Hidden, Access = public)
        function obj = MKRDCMotor(parentObj, motorNumber, varargin)
            obj.Pins = [];
            obj.Parent = parentObj;
            arduinoObj = parentObj.Parent;
            
            try
                if (nargin < 2)
                    obj.localizedError('MATLAB:minrhs');
                end
            catch e
                throwAsCaller(e);
            end
            
            motorNumber = arduinoio.internal.validateIntParameterRanged(...
                [obj.ResourceOwner 'MotorNumber'], ...
                motorNumber, ...
                1, ...
                obj.MaxDCMotors);
            
            try
                dcmotors = getSharedResourceProperty(arduinoObj, obj.ResourceOwner, 'dcmotors');
            catch 
                locDC = 1; %#ok<NASGU>
                dcmotors = [parentObj.I2CAddress zeros(1, obj.MaxDCMotors)];
            end
            carrierDCAddresses = dcmotors(:, 1);
            [~, locDC] = ismember(parentObj.I2CAddress, carrierDCAddresses);
            if locDC == 0
                dcmotors = [dcmotors; parentObj.I2CAddress zeros(1, obj.MaxDCMotors)];
                locDC = size(dcmotors, 1);
            end
            
            % Check for resource conflict with DC Motors
            if dcmotors(locDC, motorNumber+1)
                error('Arduino:MKRMotorCarrier:conflictDCMotorMKR', 'ArduinoMKRMotorCarrier\\\\DCMotor ''M%d'' is already in use', motorNumber);
            end
            dcmotors(locDC, motorNumber+1) = 1;
            setSharedResourceProperty(arduinoObj, obj.ResourceOwner, 'dcmotors', dcmotors);
            obj.MotorNumber = motorNumber;
            
            try
                p = inputParser;
                addParameter(p, 'DutyCycle', 0);
                addParameter(p, 'PWMFrequency', 100);
                parse(p, varargin{:});
            catch
                obj.localizedError('MATLAB:arduinoio:general:invalidNVPropertyName',...
                    obj.ResourceOwner, ...
                    arduinoio.internal.renderCellArrayOfCharVectorsToCharVector(p.Parameters, ', '));
            end            
            obj.DutyCycle = p.Results.DutyCycle;
            obj.PWMFrequency = p.Results.PWMFrequency;
            obj.PWMFrequency = arduinoio.internal.validateDoubleParameterRanged(...
                    'ArduinoMKRMotorCarrier\DCMotor PWMFrequency',  obj.PWMFrequency, 100, 10000);
            createDCMotor(obj);
        end
    end
    
    %%
    methods
        function start(obj)
            %   Start the DC motor.
            %
            %   Syntax:
            %   start(dev)
            %
            %   Description:
            %   Start the DC motor so that it can rotate if DutyCycle is non-zero
            %
            %   Example:
            %       a = arduino('COM7', 'Uno', 'Libraries', 'Arduino/MKRMotorCarrier');
            %       mcObj = addon(a, 'Arduino/MKRMotorCarrier');
            %       dcm = dcmotor(mcObj,1,'DutyCycle',0.3);
            %       start(dcm);
			%
            %   Input Arguments:
            %   dcm       - DC motor device 
            %
			%   See also stop
            
            try
                if obj.IsRunning == false
                    if obj.DutyCycle ~= 0
                        startDCMotor(obj);
                    end
                    obj.IsRunning = true;
                else
                    obj.localizedWarning('MATLAB:arduinoio:general:dcmotorAlreadyRunning', num2str(obj.MotorNumber));
                end
            catch e
                throwAsCaller(e);
            end
        end
        
        function stop(obj)
            %   Stop the DC motor.
            %
            %   Syntax:
            %   stop(dev)
            %
            %   Description:
            %   Stop the DC motor if it has been started
            %
            %   Example:
            %       a = arduino('COM7', 'Uno', 'Libraries', 'Arduino/MKRMotorCarrier');
            %       mcObj = addon(a, 'Arduino/MKRMotorCarrier');
            %       dcm = dcmotor(mcObj,1,'DutyCycle',0.3);
            %       start(dcm);
            %       stop(dcm);
			%
            %   Input Arguments:
            %   dcm       - DC motor device 
            %
			%   See also start
            
            try
                if obj.IsRunning == true
                    stopDCMotor(obj);
                    obj.IsRunning = false;
                end
            catch e
                throwAsCaller(e);
            end
        end
        
        function set.DutyCycle(obj, DutyCycle)
            % Valid DutyCycle range is -1 to 1
            try
                if (nargin < 2)
                    obj.localizedError('MATLAB:minrhs');
                end
            
                DutyCycle = arduinoio.internal.validateDoubleParameterRanged(...
                    'ArduinoMKRMotorCarrier\DCMotor DutyCycle', DutyCycle, -1, 1);
                
                if DutyCycle == -0
                    DutyCycle = 0;
                end
                
                if obj.IsRunning == true %#ok<MCSUP>
                    convertedDutyCycle = round(DutyCycle*100);
                    setDutyCycleDCMotor(obj, convertedDutyCycle);
                end
                obj.DutyCycle = DutyCycle;
            catch e
                throwAsCaller(e);
            end
        end
        function setPosition(obj, position)
            try
                if (obj.MotorNumber > 2)
                    error('Arduino:MKRMotorCarrier:InvalidPIDMotor', 'Invalid motor ''M%d'' for PID control. Valid motors are M1 and M2', obj.MotorNumber);
                end
                if(obj.Parent.EncoderExists(obj.MotorNumber))
                    if (nargin < 2)
                        obj.localizedError('MATLAB:minrhs');
                    end
                    position = arduinoio.internal.validateIntParameterRanged(...
                        'ArduinoMKRMotorCarrier\DCMotor Position', position, -2^15,2^15-1);
                    if obj.IsRunning == true
                        if obj.DutyCycle ~= 0
                            obj.DutyCycle = 0;
                            sWarningBacktrace = warning('off', 'backtrace');
                            warning('Arduino:MKRMotorCarrier:DutyCycleUpdated', 'ArduinoMKRMotorCarrier\\\\ ''M%d'' DutyCycle set to 0', obj.MotorNumber);
                            warning(sWarningBacktrace.state, 'backtrace');
                        end
                        setPositionDCMotor(obj, position);
                    end
                else
                    error('Arduino:MKRMotorCarrier:EncoderObjectAbsent', 'Create ArduinoMKRMotorCarrier\\\\ ''Encoder%d'' object to run DCMotor ''M%d'' in PID control mode', obj.MotorNumber, obj.MotorNumber);
                end
            catch e
                throwAsCaller(e);
            end
        end
        function setSpeed(obj, speed)
            try
                if (obj.MotorNumber > 2)
                    error('Arduino:MKRMotorCarrier:InvalidPIDMotor', 'Invalid motor ''M%d'' for PID control. Valid motors are M1 and M2', obj.MotorNumber);
                end
                if(obj.Parent.EncoderExists(obj.MotorNumber))
                    if (nargin < 2)
                        obj.localizedError('MATLAB:minrhs');
                    end 
                    speed = arduinoio.internal.validateIntParameterRanged(...
                            'ArduinoMKRMotorCarrier\DCMotor Velocity', speed, -250,250); % raw values supported only between -50 - 50
                    speed = (speed * 1200)/(100 * 60); % convert RPM to counts per centisecond. 1200 is the pulse per rev of the encoder shaft
                    if obj.IsRunning == true
                        if obj.DutyCycle ~= 0
                            obj.DutyCycle = 0;
                            sWarningBacktrace = warning('off', 'backtrace');
                            warning('Arduino:MKRMotorCarrier:DutyCycleUpdated', 'ArduinoMKRMotorCarrier\\\\ ''M%d'' DutyCycle set to 0', obj.MotorNumber);
                            warning(sWarningBacktrace.state, 'backtrace');
                        end
                        setSpeedDCMotor(obj,speed);
                    end
               else
                    error('Arduino:MKRMotorCarrier:EncoderObjectAbsent', 'Create ArduinoMKRMotorCarrier\\\\ ''Encoder%d'' object to run DCMotor ''M%d'' in PID control mode', obj.MotorNumber, obj.MotorNumber);
               end
            catch e
                throwAsCaller(e);
            end
        end
        function out = get.ConvertedDutyCycle(obj)
            % Convert DutyCycle from range [-1, 1] to [-100 100] as required by motorCarrier
            out = round(obj.DutyCycle * 100);
        end
    end
    
	%% Destructor
    methods (Access=protected)
        function delete(obj)
            originalState = warning('off','MATLAB:class:DestructorError');
            try
                parentObj = obj.Parent;
                arduinoObj = parentObj.Parent;
                
                % Clear the DC Motor
                if ~isempty(obj.MotorNumber)
                    stopDCMotor(obj);
                end
                dcmotors = getSharedResourceProperty(arduinoObj, obj.ResourceOwner, 'dcmotors');
                carrierDCAddresses = dcmotors(:, 1);
                [~, locDC] = ismember(parentObj.I2CAddress, carrierDCAddresses);
                dcmotors(locDC, obj.MotorNumber+1) = 0;
                setSharedResourceProperty(arduinoObj, obj.ResourceOwner, 'dcmotors', dcmotors);
                
                
            catch
                % Do not throw errors on destroy.
                % This may result from an incomplete construction.
            end
            warning(originalState.state, 'MATLAB:class:DestructorError');
        end
    end
    
    %% Private methods
    methods (Access = private)
        function createDCMotor(obj)
             commandID = obj.CREATE_DC_MOTOR;
             params = [obj.PWMFrequency];
             sendCommand(obj, commandID, params);
        end
        
        function startDCMotor(obj)
            commandID = obj.START_DC_MOTOR;
            dutycycle = (obj.ConvertedDutyCycle);
            params = typecast(int16(dutycycle),'uint8');
            sendCommand(obj, commandID, params');
        end
        
        function stopDCMotor(obj)
            commandID = obj.STOP_DC_MOTOR;            
            params = [];
            sendCommand(obj, commandID, params);
        end
        
        function setDutyCycleDCMotor(obj, DutyCycle)
            commandID = obj.SET_DUTYCYCLE_DC_MOTOR;
            params = typecast(int16(DutyCycle),'uint8');
            sendCommand(obj, commandID, params');
        end  
        
        function setSpeedDCMotor(obj, speed)
            commandID = obj.SET_DCM_VELOCITY;
            params = typecast(int16(speed),'uint8');
            sendCommand(obj, commandID, params');
        end
        
        function setPositionDCMotor(obj, position)
            commandID = obj.SET_DCM_POSITION;
            params = typecast(int16(position),'uint8');
            sendCommand(obj, commandID, params');
        end
    end
    
    
    %% Protected methods
    methods(Access = protected)    
        function output = sendCommand(obj, commandID, params)
            params = [obj.MotorNumber - 1; params]; 
            output = sendCarrierCommand(obj.Parent, commandID, params);
        end
    end
        
    %% Protected methods
    methods (Access = protected)
        function displayScalarObject(obj)
            header = getHeader(obj);
            disp(header);
            
            % Display main options
            fprintf('    MotorNumber: %d (M%d)\n', obj.MotorNumber, obj.MotorNumber);
            fprintf('      DutyCycle: %-15.2f\n', obj.DutyCycle);
            fprintf('      IsRunning: %-15d\n', obj.IsRunning);  
            fprintf('\n');
                  
            % Allow for the possibility of a footer.
            footer = getFooter(obj);
            if ~isempty(footer)
                disp(footer);
            end
        end
    end
end