Skip to content
Snippets Groups Projects
Select Git revision
  • 024e502e94fdfe66fd4fdebd975fd3bd4acd9522
  • master default protected
  • dev_2022
  • patch-1
  • develop
  • 50-use-ubuntus-libhidapi
  • issue-highLevelDispatch
  • issue-highLevelDesign
  • issue-motorStartBug
  • issue-commandLayerDesign
  • v1.0
  • v0.4-rc.13
  • v0.4-rc.12
  • v0.4-rc.11
  • v0.4-rc.10
  • v0.4-rc.9
  • v0.3-rc.8
  • v0.3-rc.7
  • v0.3-rc.6
  • v0.3-rc.5
  • v0.3-rc.4
  • v0.3-rc.3
  • v0.3-rc.2
  • v0.3-rc.1
  • v0.3-rc
  • v0.2
  • v0.1.1
  • v0.1
28 results

Sensor.m

Blame
  • Tim Stadtmann's avatar
    Tim Stadtmann authored
    Renamed tachoLimit back to limitValue, fixed comments and minor bugs, and
    made commInterface private.
    024e502e
    History
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    Sensor.m 13.66 KiB
    classdef Sensor < handle
        % Sensor High-level class to work with sensors.
        %
        % Properties:
        %   Standard
        %       debug           - Debug mode turned on or off
        %       mode            - Sensor mode in which the values will be read
        %   Dependent
        %       value           - Value read from sensor
        %       type            - Type of connected sensor if any
        %
        % Methods:
        %   Standard
        %       EV3             
        %       connect         - Connects Sensor-object to physical brick
        %       disconnect      - Disconnects Sensor-object from physical brick
        %       reset           - Resets value on sensor
        %       setProperties   - Sets multiple Sensor properties at once using MATLAB's inputParser
        %
        % Example
        %  % This small example should only roughly demonstrate how to work with sensors.
        %  % Establish connection, set properties on sensor1 and wait, until user has pressed the 
        %  % touch sensor ten times. Then beep and disconnect.
        %
        %  b = EV3();
        %  b = EV3('debug', 'on', 'batteryMode', 'Voltage');
        %  b.connect('bt', 'serPort', '/dev/rfcomm0');
        %  b.sensor1.mode = DeviceMode.Touch.Bumps;
        %  while value < 10
        %     pause(0.1);
        %  end
        %  b.beep();
        %  b.disconnect();
        %  b.delete()
        %
        %
        % Signature
        %  Author: Tim Stadtmann
        %  Date: 2016/05/20
        %  Updated: 2016/08/15
        
        properties  % Standard properties to be set by user
            %mode -  Sensor mode in which the value will be read
            %   -> DeviceMode.[...] (except for DeviceMode.Motor.[...])
            mode;
            
            %debug -  Debug turned on or off
            % In debug mode, everytime a command is passed to the sublayer ('communication layer'),
            % there is feedback in the console about what command has been called, etc.
            %   -> Any valid boolean (0/1/'on'/'off'/'true'/'false')
            debug;
        end
        
        properties (SetAccess = 'private')
            %port -  Sensor port
            % This is only the string representation of the sensor port to work with.
            % Internally, SensorPort-enums are used.
            %   -> '1' / '2' / '3' / '4'
            port; 
        end
        
        properties (Dependent)  % Parameters to be read directly from physical brick
            value;  % Value read from sensor
            type;  % Physical sensor connected to this port?
        end
    
        properties (Hidden, Access = 'private')  % Hidden properties for internal use only 
            commInterface = 0;  % Communication interface
            
            %% Miscallenous flags
            
            connectedToBrick = false;  % Does (virtual) sensor-object have a valid brick-handle?
            init = true;  % Indicates 'init-phase' (True as long as constructor is running)
        end   
        
        properties (Hidden, Dependent, Access = 'private')
            physicalSensorConnected;  % Physical sensor connected to this port?
        end
        
        methods  % Standard methods
            %% Constructor
            function sensor = Sensor(varargin)
                sensor.setProperties(varargin{1:end});
    			sensor.init = false;
            end
            
            %% Brick functions
            function reset(sensor)
                %reset Resets value on sensor
    			% Note: This clears ALL the sensors right now, no other Op-Code available... :(
                if ~sensor.connectedToBrick
                    error(['Sensor::reset: Sensor-Object not connected to comm handle.',...
                           'You have to call sensor.connect(commInterface) first!']);
                elseif ~sensor.physicalSensorConnected
                    error('Sensor::reset: No physical sensor connected to Port %d.',...
                           sensor.port+1);
                end
                
                warning(['Sensor::reset: Current version of reset resets ALL devices, that is, ',...
                         'all motor tacho counts and all other sensor counters!']);
                sensor.commInterface.inputDeviceClrAll(0);
                
                if sensor.debug
                    fprintf('(DEBUG) Sensor::reset: Called inputReadSI on Port %d.\n',...
                        sensor.port+1);
                end
            end
            
            %% Setter
            function set.mode(sensor, mode)
                if strcmp(class(mode),'DeviceMode.Default') && ~sensor.physicalSensorConnected
                    sensor.mode = mode;
                    return;
                end
                
                type = sensor.type;
                if ~isModeValid(mode, type)
                    error('Sensor::set.mode: Invalid sensor mode.');
                else
                    sensor.mode = mode;
                    
                    if ~strcmp(class(mode),'DeviceMode.Default') && sensor.connectedToBrick 
                        try
                            sensor.setMode(mode);  % Update physical brick's mode parameter
                        catch
                            % Ignore
                        end
                    end
                end
            end
            
            function set.debug(sensor, debug)
                % Check if debug is valid and set sensor.debug if it is.
                if ~isBool(debug)
                    error('Sensor::set.debug: Given parameter is not a bool.');
                end
                
                sensor.debug = str2bool(debug);
            end
            
            function set.port(sensor, port)
                if ~isPortStrValid(class(sensor),port)
                    error('Sensor::set.port: Given port is not a valid port.');
                else
                    sensor.port = str2PortParam(class(sensor), port);
                end
            end
            
            function set.commInterface(sensor, comm)
                if ~isCommInterfaceValid(comm)
                    error('Sensor::set.commInterface: Handle to commInterface not valid.');
                else
                    sensor.commInterface = comm;
                end
            end
            
            function setProperties(sensor, varargin)
                %setProperties Sets multiple Sensor properties at once using MATLAB's inputParser.
                %
                % Arguments
                %  * 'debug', 0/1/'on'/'off'/'true'/'false'
                %  * 'mode', DeviceMode.[...]
                %
                % Example
                %  b = EV3(); 
                %  b.connect('bt', 'serPort', '/dev/rfcomm0');
                %  b.sensor1.setProperties('debug', 'on', 'mode', DeviceMode.Color.Ambient);
                %  % Instead of: b.sensor1.debug = 'on'; 
                %  %             b.sensor1.mode = DeviceMode.Color.Ambient;
                %
                
                p = inputParser();
                
                % Set default values
                if sensor.init
                    defaultDebug = 0;
                    defaultMode = DeviceMode.Default.Undefined;
                else
                    defaultDebug = sensor.debug;
                    defaultMode = sensor.mode;
                end
                
                % Add parameter
                if sensor.init
                    p.addRequired('port');
                end
                p.addOptional('debug', defaultDebug);
                p.addOptional('mode', defaultMode);
                
                % Parse...
                p.parse(varargin{:});
                
                % Set properties
                if sensor.init
                    sensor.port = p.Results.port;
                end
                sensor.mode = p.Results.mode;
                sensor.debug = p.Results.debug;
            end
            
            %% Getter
            function value = get.value(sensor)
                value = 0;
                if strcmp(class(sensor.mode), 'DeviceMode.Default') || ... 
                        ~isModeValid(sensor.mode, sensor.type)
                    warning('Sensor::get.value: Cannot read sensor values in current mode.'); 
                    return;
                end
                
                if sensor.connectedToBrick
                    try
                        value = sensor.getValue();
                    catch
                        warning('Sensor::get.value: Could not detect sensor at port %d.', ...
                            sensor.port+1);
                        return;
                    end
                end
            end
            
            function conn = get.physicalSensorConnected(sensor)
                currentType = sensor.type;
                conn = (currentType<DeviceType.Unknown && ... 
                    (currentType~=DeviceType.MediumMotor && currentType~=DeviceType.LargeMotor));
            end
            
            function sensorType = get.type(sensor)
                if sensor.connectedToBrick
                    [sensorType, ~] = sensor.getTypeMode(); 
                else
                    sensorType = DeviceType.Unknown;
                end
            end
            
            %% Display
            function display(sensor)
                warning('off','all');
                builtin('disp', sensor);
                warning('on','all');
            end
        end
        
        methods (Access = 'private')  % Private brick functions that are wrapped by dependent params
            function setMode(sensor, mode)
                if ~sensor.connectedToBrick
                    error(['Sensor::getTachoCount: Sensor-Object not connected to comm handle.',...
                           'You have to call sensor.connect(commInterface) first!']);
                elseif ~sensor.physicalSensorConnected
                    error('Sensor::getTachoCount: No physical sensor connected to Port %d',...
                           sensor.port+1);
                end
                
                sensor.commInterface.inputReadSI(0, sensor.port, mode);  % Reading a value implicitly
                                                                 % sets the mode.
                
                if sensor.debug
                    fprintf('(DEBUG) Sensor::setMode: Called inputReadSI on Port %d.\n',...
                        sensor.port+1);
                end
            end
            
            function val = getValue(sensor)
                %getValue Reads value from sensor
                % 
                % Notes
                %  * After changing the mode, sensors initially always send an invalid value. In
                %    this case, the inputReadSI-opCode is sent again to get the correct value.
                %
                
                if ~sensor.connectedToBrick
                    error(['Sensor::getValue: Sensor-Object not connected to comm handle.',...
                           'You have to call sensor.connect(commInterface) first!']);
    %             elseif ~sensor.physicalSensorConnected
    %                 error('Sensor::getValue: No physical sensor connected to Port %d.',...
    %                        sensor.port+1);
                end
                
                val = sensor.commInterface.inputReadSI(0, sensor.port, sensor.mode);
                
                if strcmp(class(sensor.mode), 'DeviceMode.Color')
                    if sensor.mode == DeviceMode.Color.Col
                        val = Color(val);
                    end
                end
                
    			if isnan(val)
    				pause(0.01);
    				val = sensor.commInterface.inputReadSI(0, sensor.port, sensor.mode);
    				if isnan(val)
    					warning('Sensor::getValue: Brick returned invalid value (NaN). Try again...');
    				end
    			end
    			
                if sensor.debug
                    fprintf('(DEBUG) Sensor::getValue: Called inputReadSI on Port %d.\n',...
                        sensor.port+1);
                end
            end
            
            function status = getStatus(sensor)
               if ~sensor.connectedToBrick
                    error(['Sensor::getStatus: Sensor-Object not connected to comm handle.',...
                           'You have to call sensor.connect(commInterface) first!']);
               end
               
                statusNo = sensor.commInterface.inputDeviceGetConnection(0, sensor.port);
                status = ConnectionType(statusNo);
                
                if sensor.debug
                    fprintf(['(DEBUG) Sensor::getStatus: Called inputDeviceGetConnection on ' ,...
                             'Port %d.\n'], sensor.port+1);
                end
            end
            
            function [type,mode] = getTypeMode(sensor)
               if ~sensor.connectedToBrick
                    error(['Sensor::getTypeMode: Sensor-Object not connected to comm handle.',...
                           'You have to call sensor.connect(commInterface) first!']);
               end
               
                [typeNo,modeNo] = sensor.commInterface.inputDeviceGetTypeMode(0, sensor.port);
                type = DeviceType(typeNo);
                try
                    mode = DeviceMode(type,modeNo);
                catch ME
                    mode = DeviceMode.Default.Undefined;
                end
                
                if sensor.debug
                    fprintf(['(DEBUG) Sensor::getStatus: Called inputDeviceGetConnection on ' ,...
                             'Port %d.\n'], sensor.port+1);
                end
            end
        end
        
        methods (Access = {?EV3})
            function connect(sensor,commInterface)
                %connect Connects Sensor-object to physical brick
                
                if sensor.connectedToBrick
                    if isCommInterfaceValid(sensor.commInterface)
                        error('Sensor::connect: Sensor-Object already has a comm handle.');
                    else
                        warning(['Sensor::connect: Sensor.connectedToBrick is set to ''True'', but ',...
                            'comm handle is invalid. Deleting invalid handle and ' ,...
                            'resetting Sensor.connectedToBrick now...']);
                        
                        sensor.commInterface = 0;
                        sensor.connectedToBrick = false;
                        
                        error('Sensor::connect: Disconnected due to internal error.');
                    end
                end
                
                sensor.commInterface = commInterface;
                sensor.connectedToBrick = true;
                
                if sensor.debug
                    fprintf('(DEBUG) Sensor-Object connected to comm handle.\n');
                end
            end
            
            function disconnect(sensor)
                %disconnect Disconnects Sensor-object from physical brick
                
                sensor.commInterface = 0; % Note: actual deleting is done in EV3::disconnect.
                sensor.connectedToBrick = false;
            end
        end
    end