Aufgrund einer Wartung wird GitLab am 29.10. zwischen 9:00 und 10:00 Uhr kurzzeitig nicht zur Verfügung stehen. / Due to maintenance, GitLab will be temporarily unavailable on 29.10. between 9:00 and 10:00 am.

test_itaEimarMotorControl.m 12.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
classdef test_itaEimarMotorControl < itaMeasurementTasksScan
    % Measurements with the ITA Italian Turntable (Nanotec motors), ITA Arm and the ITA Slayer
    %
    %
    
    % *********************************************************************
    %
    % E = Everything
    % I = Is
    % M = Moving
    % A = And
    % R = Rotating
    %
    % *********************************************************************
    %
16 17
    % BE AWARE: THE MOTOR CONTROL HAS BEEN SEPARATED FROM THE ORIGINAL
    % itaEimar
18
    %
19
    % Author:       Jan-Gerrit Richter (jri@akustik.rwth-aachen.de)
20
    %
21
    % itaEimar:     Benedikt Krechel - November-June 2012
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
    %               Johannes Klein - March/April/May 2012
    %
    % Contact:      Benedikt.krechel@rwth-aachen.de
    %               Johannes.klein@rwth-aachen.de
    %
    %
    % Special thanks to: Oliver Strauch for changing the e in Eimer to an a!
    %
    % *********************************************************************
    % *********************************************************************
    %
    % HOW TO USE:
    %
    % iMS = itaEimar;
    % -> Will call init and give note about which motor is connected.
    %
    % IMPORTANT COMMAND:
    % -  iMS.stop
    %
    % Make the reference move:
    % ( - without this you are not allowed to move the arm or the slayer (but the turntable)! - )
    % -  iMS.reference
    %
    % Move commands:
46 47
    %   This lets the motor decide what part of the coordinates it is
    %   responsible for
48 49 50
    % -  iMS.moveTo( itaCoordinate Object )
    %
    % Separate move commands:
51
    % -  iMS.moveTo(MotorName, step in degrees)
52 53 54 55 56 57 58 59 60 61 62 63 64 65
    %
    % ************************************
    % STATIC MEASUREMENT:
    %
    % How to prepare the measurement:
    % -  iMS.measurementPositions = ita_sph_sampling_gaussian(30); (i.e.)
    % -  iMS.measurementSetup = [ YOUR MEASUREMENT SETUP i.e. itaMSTF ]
    % -  iMS.dataPath = [ PATH / FOLDER FOR RESULTS ]
    %
    % Run measurement
    % -  iMS.run
    %
    %
    % ************************************
66 67 68 69 70 71 72 73 74 75 76
    % CONTINUOUS MEASUREMENT:
    %
    %   This moves the arc into reference, then moves some angle against
    %   the turn direction and sends all commands but start for the full
    %   rotation
    % -  iMS.prepareForContinuousMeasurement;
    %   
    %   Starts the previously prepared rotation and measures
    %    iMS.runContinuousMeasurement;
    %   
    %   See ita_tutorial_hrtfMeasurement
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
    %
    % Run measurement
    % -  iMS.run
    %
    % *********************************************************************
    %
    % <ITA-Toolbox>
    % This file is part of the application Movtec for the ITA-Toolbox. All rights reserved.
    % You can find the license for this m-file in the application folder.
    % </ITA-Toolbox>
    
    properties
        doSorting           =     true;   % sort the measurement coordinates for arm due to shorter measurement time 
    end
    % *********************************************************************
    properties (Access = protected, Hidden = true)
93
        actual_status       =   []; % Store status - don't send the same command again!
94 95 96 97 98 99 100 101 102
        old_position        =   itaCoordinates(2); % Avoid to move two times to the same position
        wait                =   true;        % Status - do we wait for motors to reach final position? -> Set by prepare-functions!
        
        mMotorControl = [];
    end
    % *********************************************************************
    properties(Constant, Hidden = true)

    end
103
    
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
    methods
        %% -----------------------------------------------------------------
        % Basic stuff:
        function this = test_itaEimarMotorControl(varargin)
            % Constructor
            this.init;
        end
        function reset(this)
            %reset the Object. Ready to start from scatch again...
            this.clear_actual_status;
            this.mIsInitialized     =   false;
            this.mCurrentPosition   =   cart2sph(itaCoordinates(1));
            this.mLastMeasurement   =   0;
        end
        
        function clear_actual_status(this)
            % Clear confirmed commands which do not need to be send again.
            % Usefull if motor is turned off and on while class-object in
            % Matlab remains without a change.
            this.actual_status   =   [];
        end
 %         
        function init(this, varargin)
            % Initialize class
            
            %do a reset and also reset the serialObj
            this.reset(); % Do a reset first.
            this.actual_status           =   [];



             
            % Init RS232 and return handle
            try
                if isempty(this.measurementSetup)
                elseif isempty(this.measurementSetup) && isempty(this.measurementSetup.inputMeasurementChain(1).coordinates.x)
                    for idx = 1:numel(this.measurementSetup.inputMeasurementChain)
                        this.measurementSetup.inputMeasurementChain(idx).coordinates = itaCoordinates([0 0 0]);
                    end
                end
                
            % init the motorclass object;
            this.mMotorControl = itaMotorControlNanotec;
            this.mIsInitialized = true;

            catch errmsg
%                 this.mIsInitialized                     =   false;
                ita_verbose_info(errmsg.message,0);
                error('i: Unable to initialize correctly');
            end
            
            % subfolder for data - speed reasons for lots of files
            if ~isdir(this.finalDataPath)
                mkdir(this.finalDataPath);
            end
        end
160 161
        
        
162 163 164 165 166 167 168 169
        %% -----------------------------------------------------------------
        % Reference stuff:
        function reference(this)
            % Move to reference position
            ita_verbose_info('Everything is moving... (TAKE CARE OF YOUR HEAD!)',0);
            this.mMotorControl.reference;
            ita_verbose_info('Reference done!',1);
        end
170 171
        
        
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
        %% -----------------------------------------------------------------
        % Move commands:
        function stop(this)
            % DO NOT ASK - JUST STOP ALL MOTORS!
            for i = 1:5 % repeat several times to ensure that every motor stops!
                this.mMotorControl.stopAllMotors;
            end
        end
        
        function moveTo(this,varargin)
            % Check if it is initialized:
            if ~this.isInitialized
                ita_verbose_info('Not initialized - I will do that for you...!',0);
                this.initialize
            end
            % Check if it is referenced:
            if ~this.isReferenced
                % Otherwise warn the user that the reference is at power-up
                % position:
                ita_verbose_info('Be aware! No reference move done! Reference = Power-Up-Position!',2)
            end
            
194
            % let the motor control do the move
195 196 197
            this.mMotorControl.moveTo(varargin{:});
        end
  
198
        function prepareContinuousMeasurement(this,varargin)
Jan-Gerrit Richter's avatar
Jan-Gerrit Richter committed
199 200 201 202 203
            
            if isempty(this.measurementSetup)
                error('Measurement Setup is unset')
            end
            
204
            % calculate the pre angle
Jan-Gerrit Richter's avatar
Jan-Gerrit Richter committed
205 206
            % the pre angle is needed because the measurement setup will
            % not start recording imidiately
207 208 209 210 211
            numRepetitions = this.measurementSetup.repititions;
            timePerRepetition = this.measurementSetup.twait*length(this.measurementSetup.outputChannels);
            speed   =   360/(numRepetitions*timePerRepetition);

            % preangletime
Jan-Gerrit Richter's avatar
Jan-Gerrit Richter committed
212
            preAngleTime = 2/64*numRepetitions; % it takes 2 seconds to start recording
213 214 215
            preAngle = preAngleTime*speed;

            preAngle = min(preAngle,15);
216
            preAngle = max(preAngle,8);
Jan-Gerrit Richter's avatar
Jan-Gerrit Richter committed
217
            numTotalRepetitions = numRepetitions+ceil(preAngleTime/(timePerRepetition))+9;
218
            this.measurementSetup.repititions = numTotalRepetitions;
219 220
            
            %prepare motors for continuous measurement
221
            this.mMotorControl.prepareForContinuousMeasurement('speed',speed,'preAngle',preAngle);
222
            
Jan-Gerrit Richter's avatar
Jan-Gerrit Richter committed
223
            % calculate the excitation as this takes quite a long time
224
            this.measurementSetup.excitation;
Jan-Gerrit Richter's avatar
Jan-Gerrit Richter committed
225 226
            
            % pre init playrec to save the second delay
227 228
            if playrec('isInitialised')
                playrec('reset');
229
            end
230
            playrec('init', this.measurementSetup.samplingRate, 0, 0);
231 232 233 234 235
            
            
        end
        
        
236
        function [result, result_raw] = runContinuousMeasurement(this)
237 238
            this.mMotorControl.setWait(false);
            this.mMotorControl.startContinuousMoveNow;
Jan-Gerrit Richter's avatar
Jan-Gerrit Richter committed
239
            pause(1);
240 241
            result_raw = this.measurementSetup.run_raw_imc;
            result = this.measurementSetup.deconvolve(result_raw);
Jan-Gerrit Richter's avatar
Jan-Gerrit Richter committed
242
%             this.stop;
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
            this.mMotorControl.setWait(true);
        end
        
        function motorControl = getMotorControl(this)
           motorControl = this.mMotorControl; 
        end
        %% -----------------------------------------------------------------
        % GUI:
        function gui(this) %#ok<*MANU>
            %call GUI
            errordlg('There is no GUI - sorry! But you can build one if you like!')
        end
        
    end %% methods
    % *********************************************************************
    % *********************************************************************
    methods(Hidden = true)
        % Sort measurement positions and delete points outside of the allowed range:
        function this = sort_measurement_positions(this,varargin)
            ita_verbose_info('I will sort your measurement positions for better performance.', 1);
            % Delete every point below ARM_limit:
            this.measurementPositions = this.measurementPositions.n(this.measurementPositions.theta <= this.ARM_limit(2)/180*pi);
            this.measurementPositions = this.measurementPositions.n(this.measurementPositions.theta >= this.ARM_limit(1)/180*pi);
            % Sort:
            this.measurementPositions = this.do_coordinate_sorting(this.measurementPositions); 
        end
 
%         % -----------------------------------------------------------------
        function res = finalDataPath(this)
            % Final data path string
            res                 =   [this.dataPath filesep 'data'];
        end
        %-----------------------------------------------------------------

        
        function run(this)
            if this.doSorting
                this.sort_measurement_positions();
            end
            run@itaMeasurementTasksScan(this);
        end
        
    end
    methods(Static)
        function s = do_coordinate_sorting(s)
            % phi should be between -pi..pi
            %             s.phi = mod(s.phi + pi, 2*pi) - pi;
            s.phi(s.phi > pi) = s.phi(s.phi > pi) - 2*pi;
            
            % sort the phi angles in both directions
            [~, index_phi_ascend] = sort(round_tol(s.phi), 'ascend');
            [~, index_phi_descend] = sort(round_tol(s.phi), 'descend');
            % sort the theta angles
            [~, index_theta_phi_ascend] = sort(s.theta(index_phi_ascend), 'descend');
            [~, index_theta_phi_descend] = sort(s.theta(index_phi_descend), 'descend');
            
            % get a list of unique elevation angles
            unique_theta = unique(round_tol(s.theta));
            
            % this is the complete coordinates sorted with ascending and
            % descending phi angle
            sph_ascend = s.sph(index_phi_ascend(index_theta_phi_ascend),:);
            sph_descend = s.sph(index_phi_descend(index_theta_phi_descend),:);
            
            % check when we want to use ascending, when descending
            isAscending = ismember(round_tol(sph_ascend(:,2)), unique_theta(1:2:end));
            % the last row with the lowest theta (at the beginning of the
            % unique-list) should be ascending in order to avoid problems
            % with the reference move later on
            
            % overwrite the data to the coordinates object
            s.sph(isAscending,:) = sph_ascend(isAscending,:);
            s.sph(~isAscending,:) = sph_descend(~isAscending,:);
            
%             % phi should be again between 0..2*pi
%             s.phi = mod(s.phi, 2*pi);
            
            function theta = round_tol(theta)
                constant = 1e10;
                theta = round(theta * constant) / constant;
            end
        end
    end
end