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 13.9 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
        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 = [];
98
        mRepetitionsSave = 0;
99 100 101 102 103
    end
    % *********************************************************************
    properties(Constant, Hidden = true)

    end
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 160
    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
161 162
        
        
163 164 165 166 167 168 169 170
        %% -----------------------------------------------------------------
        % 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
171 172
        
        
173 174 175 176 177 178 179 180 181 182 183
        %% -----------------------------------------------------------------
        % 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:
184
%             varargin{1}.phi_deg
185 186 187 188 189 190 191 192 193 194 195
            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
            
196
            % let the motor control do the move
197 198 199
            this.mMotorControl.moveTo(varargin{:});
        end
  
200
        function prepareContinuousMeasurement(this,varargin)
Jan-Gerrit Richter's avatar
Jan-Gerrit Richter committed
201 202 203 204 205
            
            if isempty(this.measurementSetup)
                error('Measurement Setup is unset')
            end
            
206
            % calculate the pre angle
Jan-Gerrit Richter's avatar
Jan-Gerrit Richter committed
207 208
            % the pre angle is needed because the measurement setup will
            % not start recording imidiately
209
            numRepetitions = this.measurementSetup.repetitions;
210
            this.measurementSetup.repetitions = numRepetitions;
211 212
            timePerRepetition = this.measurementSetup.twait*length(this.measurementSetup.outputChannels);
            speed   =   360/(numRepetitions*timePerRepetition);
213 214 215 216 217 218 219
            motorControl = this.getMotorControl;
            motorName = motorControl.motorList{1}.getMotorName;
            
            if strcmp(motorName,'HRTFArc')
                % preangletime
                preAngle = 45;
                preAngleTime = preAngle/speed; % it takes 2 seconds to start recording
220

221 222
                postAngle = -35;
                postAngleTime = postAngle/speed;
223

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
                additionalReps = ceil((postAngleTime+preAngleTime + 1)/timePerRepetition);
                numTotalRepetitions = numRepetitions+additionalReps;
                this.measurementSetup.repetitions = numTotalRepetitions;
            else
                % preangletime
                preAngle = 15;
                preAngleTime = preAngle/speed; % it takes 2 seconds to start recording

                postAngle = 5;
                postAngleTime = postAngle/speed;

                additionalReps = ceil((postAngleTime+preAngleTime + 1)/timePerRepetition);
                numTotalRepetitions = numRepetitions+additionalReps;
                this.measurementSetup.repetitions = numTotalRepetitions;    
                
            end
240
            %prepare motors for continuous measurement
241
            this.mMotorControl.prepareForContinuousMeasurement('speed',speed,'preAngle',preAngle,'postAngle',postAngle);
242
            
Jan-Gerrit Richter's avatar
Jan-Gerrit Richter committed
243
            % calculate the excitation as this takes quite a long time
244
            this.measurementSetup.excitation;
Jan-Gerrit Richter's avatar
Jan-Gerrit Richter committed
245 246
            
            % pre init playrec to save the second delay
247 248
            if playrec('isInitialised')
                playrec('reset');
249
            end
250
            playrec('init', this.measurementSetup.samplingRate, 0, 0);
251 252 253 254 255
            
            
        end
        
        
256
        function [result, result_raw] = runContinuousMeasurement(this)
257 258
            this.mMotorControl.setWait(false);
            this.mMotorControl.startContinuousMoveNow;
259
            pause(0.1);
260 261
            result_raw = this.measurementSetup.run_raw_imc;
            result = this.measurementSetup.deconvolve(result_raw);
Jan-Gerrit Richter's avatar
Jan-Gerrit Richter committed
262
%             this.stop;
263
            this.mMotorControl.setWait(true);
264
            this.measurementSetup.repetitions = this.mRepetitionsSave;
265 266 267
            % add history line
            commitID = ita_git_getMasterCommitHash;
            if ~isempty(commitID)
268 269 270
               result_raw = ita_metainfo_add_historyline(result_raw,'Continuous Measurement',commitID); 
               result = ita_metainfo_add_historyline(result,'Continuous Measurement',commitID); 

271
            end
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
        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
310 311
            motorList = this.mMotorControl.motorList;
            motorList{1}.disableReference(1);
312
            run@itaMeasurementTasksScan(this);
313
            motorList{1}.disableReference(0);
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
        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