function [experimentDataStruct] = generateExperimentData(robot, benchmarkSettings, options, varargin) % Authors: Quentin Leboutet, Julien Roux, Alexandre Janot and Gordon Cheng % % Experiment data generation if benchmarkSettings.experimentOnTrueRobot == true error('TODO: PLEASE REWRITE THIS PART OF THE CODE'); % Load experiment file: fileName = 'mitsu-data_1_100_05'; experimentFile = sprintf('Benchmark/Robot_Generated_Data/%s/Experiment_Data/%s.mat', benchmarkSettings.robotName, fileName); load(experimentFile); nbSamples = size(experimentData.Qm,2); t_sample = linspace(benchmarkSettings.t_i, benchmarkSettings.t_f, nbSamples); % Sampling epochs if benchmarkSettings.trajectoryData.t_f < benchmarkSettings.t_f error('Experiment data parsing: the selected time horizon (t_f = %d) is greater than that of the trajectory generator (t_f = %d)!\n', benchmarkSettings.t_f, benchmarkSettings.trajectoryData.t_f); end Taum = zeros(robot.nbDOF, nbSamples, 1); Qm = zeros(robot.nbDOF, nbSamples, 1); Qpm = zeros(robot.nbDOF, nbSamples, 1); Qppm = zeros(robot.nbDOF, nbSamples, 1); Xm = zeros(3, nbSamples, 1); Xpm = zeros(3, nbSamples, 1); Qd = zeros(robot.nbDOF, nbSamples, 1); Qpd = zeros(robot.nbDOF, nbSamples, 1); Qppd = zeros(robot.nbDOF, nbSamples, 1); Xd = zeros(3, nbSamples, 1); Xpd = zeros(3, nbSamples, 1); %% Data Parsing: augmentedDesiredState = benchmarkSettings.trajectoryData.getTrajectoryData(t_sample, benchmarkSettings.interpolationAlgorithm); % Initial state [Qp;Q] [Qd(:,:,1), Qpd(:,:,1), Qppd(:,:,1), Xd(:,:,1), Qm(:,:,1), Xm(:,:,1), Taum(:,:,1)] = parseExperimentData(robot, t_sample, augmentedDesiredState, experimentData, options, varargin); experimentDataStruct.time = linspace(benchmarkSettings.t_i, benchmarkSettings.t_f, benchmarkSettings.nbSamples); experimentDataStruct.Taum = Taum; experimentDataStruct.Qm = Qm; experimentDataStruct.Qpm = Qpm; experimentDataStruct.Qppm = Qppm; experimentDataStruct.Xm = Xm; experimentDataStruct.Xpm = Xpm; experimentDataStruct.Qd = Qd; experimentDataStruct.Qpd = Qpd; experimentDataStruct.Qppd = Qppd; experimentDataStruct.Xd = Xd; experimentDataStruct.Xpd = Xpd; else numberOfExperimentsPerInitialPoint = benchmarkSettings.numberOfExperimentsPerInitialPoint; Xhi_obj = benchmarkSettings.Xhi_obj; nbSamples = benchmarkSettings.nbSamples; nbCtrlSamples = benchmarkSettings.nbCtrlSamples; t_sample = linspace(benchmarkSettings.t_i, benchmarkSettings.t_f, nbSamples); % Sampling epochs t_ctrl = linspace(benchmarkSettings.t_i, benchmarkSettings.t_f, nbCtrlSamples); % Control epochs if benchmarkSettings.trajectoryData.t_f < benchmarkSettings.t_f error('Experiment data generation: the desired time horizon of the simulation (t_f = %d) is greater than that of the trajectory generator (t_f = %d)!\n', benchmarkSettings.t_f, benchmarkSettings.trajectoryData.t_f); end sd_q = robot.numericalParameters.sd_q; % Noise standard deviation sd_tau = robot.numericalParameters.sd_tau; % Noise standard deviation Tau = zeros(robot.nbDOF, nbSamples, numberOfExperimentsPerInitialPoint); Tau_friction = zeros(robot.nbDOF, nbSamples, numberOfExperimentsPerInitialPoint); Taum = zeros(robot.nbDOF, nbSamples, numberOfExperimentsPerInitialPoint); Q = zeros(robot.nbDOF, nbSamples, numberOfExperimentsPerInitialPoint); Qp = zeros(robot.nbDOF, nbSamples, numberOfExperimentsPerInitialPoint); Qpp = zeros(robot.nbDOF, nbSamples, numberOfExperimentsPerInitialPoint); X = zeros(3, nbSamples, numberOfExperimentsPerInitialPoint); Xp = zeros(3, nbSamples, numberOfExperimentsPerInitialPoint); Qm = zeros(robot.nbDOF, nbSamples, numberOfExperimentsPerInitialPoint); Qpm = zeros(robot.nbDOF, nbSamples, numberOfExperimentsPerInitialPoint); Qppm = zeros(robot.nbDOF, nbSamples, numberOfExperimentsPerInitialPoint); Xm = zeros(3, nbSamples, numberOfExperimentsPerInitialPoint); Xpm = zeros(3, nbSamples, numberOfExperimentsPerInitialPoint); Qd = zeros(robot.nbDOF, nbSamples, numberOfExperimentsPerInitialPoint); Qpd = zeros(robot.nbDOF, nbSamples, numberOfExperimentsPerInitialPoint); Qppd = zeros(robot.nbDOF, nbSamples, numberOfExperimentsPerInitialPoint); Xd = zeros(3, nbSamples, numberOfExperimentsPerInitialPoint); Xpd = zeros(3, nbSamples, numberOfExperimentsPerInitialPoint); %% Data Generation: augmentedDesiredState = benchmarkSettings.trajectoryData.getTrajectoryData(t_ctrl, benchmarkSettings.interpolationAlgorithm); % Initial state [Qp;Q] if numberOfExperimentsPerInitialPoint == 1 for j = 1:numberOfExperimentsPerInitialPoint [Q(:,:,j), Qp(:,:,j), Qpp(:,:,j), X(:,:,j), Xp(:,:,j), Tau(:,:,j), Tau_friction(:,:,j), ... Qd(:,:,j), Qpd(:,:,j), Qppd(:,:,j), Xd(:,:,j), Xpd(:,:,j), ... Qm(:,:,j), Qpm(:,:,j), Qppm(:,:,j), Xm(:,:,j), Xpm(:,:,j), Taum(:,:,j)] = simulateRobot(augmentedDesiredState, t_sample, benchmarkSettings.dt, t_ctrl, benchmarkSettings.dt_ctrl, Xhi_obj, nbSamples, nbCtrlSamples, robot, sd_q, sd_tau, options, j); end else parfor j = 1:numberOfExperimentsPerInitialPoint [Q(:,:,j), Qp(:,:,j), Qpp(:,:,j), X(:,:,j), Xp(:,:,j), Tau(:,:,j), Tau_friction(:,:,j), ... Qd(:,:,j), Qpd(:,:,j), Qppd(:,:,j), Xd(:,:,j), Xpd(:,:,j), ... Qm(:,:,j), Qpm(:,:,j), Qppm(:,:,j), Xm(:,:,j), Xpm(:,:,j), Taum(:,:,j)] = simulateRobot(augmentedDesiredState, t_sample, benchmarkSettings.dt, t_ctrl, benchmarkSettings.dt_ctrl, Xhi_obj, nbSamples, nbCtrlSamples, robot, sd_q, sd_tau, options, j); end end experimentDataStruct.time = linspace(benchmarkSettings.t_i, benchmarkSettings.t_f, benchmarkSettings.nbSamples); experimentDataStruct.Tau_friction = Tau_friction; experimentDataStruct.Tau = Tau; experimentDataStruct.Taum = Taum; experimentDataStruct.Q = Q; experimentDataStruct.Qp = Qp; experimentDataStruct.Qpp = Qpp; experimentDataStruct.X = X; experimentDataStruct.Xp = Xp; experimentDataStruct.Qm = Qm; experimentDataStruct.Qpm = Qpm; experimentDataStruct.Qppm = Qppm; experimentDataStruct.Xm = Xm; experimentDataStruct.Xpm = Xpm; experimentDataStruct.Qd = Qd; experimentDataStruct.Qpd = Qpd; experimentDataStruct.Qppd = Qppd; experimentDataStruct.Xd = Xd; experimentDataStruct.Xpd = Xpd; end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Robot Closed-Loop Simulation Routine: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [Q, Qp, Qpp, X, Xp, Tau, Tau_friction, Qd, Qpd, Qppd, Xd, Xpd, Qm, Qpm, Qppm, Xm, Xpm, Taum] = simulateRobot(augmentedDesiredState, t_sample, dt_sample, t_ctrl, dt_ctrl, Xhi_obj, nbSamples, nbCtrlSamples, robot, sd_q, sd_tau, options, index, varargin) % This function runs at the robot controller frequency % robot.controlParameters.controlFrequency and collect experimental data at % the sampling frequeny robot.controlParameters.samplingFrequency % Variables memory initialization: Tau = zeros(robot.nbDOF, nbSamples); Tau_friction = zeros(robot.nbDOF, nbSamples); Taum = zeros(robot.nbDOF, nbSamples); Q = zeros(robot.nbDOF, nbSamples); Qp = zeros(robot.nbDOF, nbSamples); Qpp = zeros(robot.nbDOF, nbSamples); X = zeros(3, nbSamples); Xp = zeros(3, nbSamples); Qm = zeros(robot.nbDOF, nbSamples); Qpm = zeros(robot.nbDOF, nbSamples); Qppm = zeros(robot.nbDOF, nbSamples); Xm = zeros(3, nbSamples); Xpm = zeros(3, nbSamples); Qd = zeros(robot.nbDOF, nbSamples); Qpd = zeros(robot.nbDOF, nbSamples); Qppd = zeros(robot.nbDOF, nbSamples); Xd = zeros(3, nbSamples); Xpd = zeros(3, nbSamples); % Variables initial value: Qpp(:,1) = augmentedDesiredState(1:robot.nbDOF,1); Qp(:,1) = augmentedDesiredState(robot.nbDOF+1:2*robot.nbDOF,1); Q(:,1) = augmentedDesiredState(2*robot.nbDOF+1:end,1); Qppm(:,1) = augmentedDesiredState(1:robot.nbDOF,1); Qpm(:,1) = augmentedDesiredState(robot.nbDOF+1:2*robot.nbDOF,1); Qm(:,1) = augmentedDesiredState(2*robot.nbDOF+1:end,1); Qppd(:,1) = augmentedDesiredState(1:robot.nbDOF,1); Qpd(:,1) = augmentedDesiredState(robot.nbDOF+1:2*robot.nbDOF,1); Qd(:,1) = augmentedDesiredState(2*robot.nbDOF+1:end,1); measuredState = [Qpm(:,1); Qm(:,1)]; currentState = augmentedDesiredState(robot.nbDOF+1:end,1); integralError = zeros(robot.nbDOF, 1); H = feval(sprintf('HT_dh%d_world_%s', robot.nbDOF,robot.name),Q(:,1), robot.numericalParameters.Geometry); X(:,1) = H(1:3,4); Xp(:,1) = [eye(3),zeros(3)]*feval(sprintf('J_dh%d_world_%s', robot.nbDOF,robot.name),Q(:,1), robot.numericalParameters.Geometry)*Q(:,1); Hd = feval(sprintf('HT_dh%d_world_%s', robot.nbDOF,robot.name),Qd(:,1), robot.numericalParameters.Geometry); Xd(:,1) = Hd(1:3,4); Xpd(:,1) = [eye(3),zeros(3)]*feval(sprintf('J_dh%d_world_%s', robot.nbDOF,robot.name),Qd(:,1), robot.numericalParameters.Geometry)*Qd(:,1); Hm = feval(sprintf('HT_dh%d_world_%s', robot.nbDOF,robot.name),Qm(:,1), robot.numericalParameters.Geometry); Xm(:,1) = Hm(1:3,4); Xpm(:,1) = [eye(3),zeros(3)]*feval(sprintf('J_dh%d_world_%s', robot.nbDOF,robot.name),Qm(:,1), robot.numericalParameters.Geometry)*Qm(:,1); Z = robot.numericalParameters.friction.Z0; [friction, Z] = generateFriction(Qp(:,1), Z, robot, dt_ctrl); Tau_friction(:,1) = friction; sampleIndex = 2; options.augmentedInitialState=augmentedDesiredState(:,1); options.index = index; %% Closed loop dynamics: for controlIndex = 2:nbCtrlSamples % Runs at controlFrequency and collect data at samplingFrequency if ~mod(controlIndex,1000) fprintf('Iteration %d of %d, experiment %d\n', controlIndex, nbCtrlSamples, index); end % Generate contol input: [controlInput, integralError] = computeControlInput(dt_ctrl, measuredState, augmentedDesiredState(:,controlIndex), ... integralError, robot.controlParameters.Kp, robot.controlParameters.Ki, robot.controlParameters.Kd, robot.controlParameters.Ktau, robot.controlParameters.antiWindup, ... robot.physicalConstraints.limQ_L, robot.physicalConstraints.limQ_U, robot.physicalConstraints.limQp_L, ... robot.physicalConstraints.limQp_U, robot.physicalConstraints.limQpp_L, robot.physicalConstraints.limQpp_U, ... robot.physicalConstraints.limTau_L, robot.physicalConstraints.limTau_U); % Control input generated with noisy measured state % Propagate dynamics: timeDerivativeState = computeDataGenForwardDynamics(robot.name, currentState, controlInput, Xhi_obj, robot.numericalParameters.Geometry, robot.numericalParameters.Gravity, friction); % Real robot state derivative (no added noise) when submitted to 'Tau' % Time integration between t(i-1) and t(i): forwardDynamics = @(State, controlInput) computeDataGenForwardDynamics(robot.name, State, controlInput, Xhi_obj, robot.numericalParameters.Geometry, robot.numericalParameters.Gravity, friction); switch options.integrationAlgorithm case 'rk1' currentState = rk1_IntegrationStep(forwardDynamics,currentState,controlInput,dt_ctrl); case 'rk2' currentState = rk2_IntegrationStep(forwardDynamics,currentState,controlInput,dt_ctrl); case 'rk4' currentState = rk4_IntegrationStep(forwardDynamics,currentState,controlInput,dt_ctrl); case 'ode45' [~ , Y_i] = ode45(@(t, Y) computeDataGenForwardDynamics(robot.name, Y, controlInput, Xhi_obj, robot.numericalParameters.Geometry, robot.numericalParameters.Gravity, friction), [t_ctrl(controlIndex-1) t_ctrl(controlIndex)], currentState); currentState = Y_i(end,:).'; otherwise % 'rk1' currentState = rk1_IntegrationStep(forwardDynamics,currentState,controlInput,dt_ctrl); end % Real robot state: currentState(1:robot.nbDOF) = min(robot.physicalConstraints.limQp_U,max(robot.physicalConstraints.limQp_L,currentState(1:robot.nbDOF))); % Velocity limit saturation currentState(robot.nbDOF+1:end) = min(robot.physicalConstraints.limQ_U,max(robot.physicalConstraints.limQ_L,currentState(robot.nbDOF+1:end))); % Joint limit saturation % Measured robot state, reinjected into the control loop: measured_Q = noisyMeasurement(currentState(robot.nbDOF+1:end),sd_q); % Noise applied on position measurement (encoder noise) measuredState = [discreteTimeDerivative(measured_Q,measuredState(robot.nbDOF+1:end),dt_ctrl); measured_Q]; % Discrete time derivation to get the velocity from the noisy position (as it is usually done in real digital control systems) % Compute friction: [friction, Z] = generateFriction(currentState(1:robot.nbDOF), Z, robot, dt_ctrl); % Store variables in memory at each sampling epoch: if t_ctrl(controlIndex) >= t_sample(sampleIndex) Q(:,sampleIndex) = currentState(robot.nbDOF+1:end); % Real joint position Qp(:,sampleIndex) = timeDerivativeState(robot.nbDOF+1:end); % Real joint velocity Qpp(:,sampleIndex) = timeDerivativeState(1:robot.nbDOF); % Real joint acceleration Qd(:,sampleIndex) = augmentedDesiredState(2*robot.nbDOF+1:end,controlIndex); % Desired joint position Qpd(:,sampleIndex) = augmentedDesiredState(robot.nbDOF+1:2*robot.nbDOF,controlIndex); % Desired joint velocity Qppd(:,sampleIndex) = augmentedDesiredState(1:robot.nbDOF,controlIndex); % Desired joint acceleration Qm(:,sampleIndex) = measuredState(robot.nbDOF+1:end); % Joint position measured with noisy sensor (re-injected in position control loop) Qpm(:,sampleIndex) = measuredState(1:robot.nbDOF); % Discrete time derivative of noisy joint position measurement (re-injected in position control loop) Qppm(:,sampleIndex) = discreteTimeDerivative(Qpm(:,sampleIndex),Qpm(:,sampleIndex-1),dt_sample); % Double discrete time derivative of noisy joint position measurement Tau(:,sampleIndex) = controlInput; % Real control Torque sent to the robot (without added sensor noise but computed using noisy position measurement) Taum(:,sampleIndex) = noisyMeasurement(controlInput, sd_tau); % Control Torque measured with noisy sensor (not re-injected in position control but visible in measured identification data) Tau_friction(:,sampleIndex) = friction; H = feval(sprintf('HT_dh%d_world_%s', robot.nbDOF,robot.name),Q(:,sampleIndex), robot.numericalParameters.Geometry); X(:,sampleIndex) = H(1:3,4); % Real Cartesian Position Xp(:,sampleIndex) = [eye(3),zeros(3)]*feval(sprintf('J_dh%d_world_%s', robot.nbDOF,robot.name),Q(:,sampleIndex), robot.numericalParameters.Geometry)*Qp(:,sampleIndex); % Real Cartesian Velocity Hd = feval(sprintf('HT_dh%d_world_%s', robot.nbDOF,robot.name),Qd(:,sampleIndex), robot.numericalParameters.Geometry); Xd(:,sampleIndex) = Hd(1:3,4); % Desired Cartesian Position Xpd(:,sampleIndex) = [eye(3),zeros(3)]*feval(sprintf('J_dh%d_world_%s', robot.nbDOF,robot.name),Qd(:,sampleIndex), robot.numericalParameters.Geometry)*Qpd(:,sampleIndex);% Desired Cartesian Velocity Hm = feval(sprintf('HT_dh%d_world_%s', robot.nbDOF,robot.name),Qm(:,sampleIndex), robot.numericalParameters.Geometry); Xm(:,sampleIndex) = Hm(1:3,4); % Measured Cartesian Position (with noisy sensor) Xpm(:,sampleIndex) = [eye(3),zeros(3)]*feval(sprintf('J_dh%d_world_%s', robot.nbDOF,robot.name),Qm(:,sampleIndex), robot.numericalParameters.Geometry)*Qpm(:,sampleIndex);% Measured Cartesian Velocity (with noisy sensor) sampleIndex = sampleIndex+1; if sampleIndex > numel(t_sample) sampleIndex = numel(t_sample); end end end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Robot Friction Data Simulation Routine: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [Tau_friction, Z] = generateFriction(Qp, Z, robot, dt) Friction = feval(sprintf('Friction_%s', robot.name), Qp, robot.numericalParameters.friction.Fv, robot.numericalParameters.friction.Fc, robot.numericalParameters.friction.Fvm, robot.numericalParameters.friction.Fcm, robot.numericalParameters.friction.Fs, robot.numericalParameters.friction.Vs, robot.numericalParameters.friction.Es, robot.numericalParameters.friction.Sigma_0, robot.numericalParameters.friction.Sigma_1, robot.numericalParameters.friction.Sigma_2, robot.numericalParameters.friction.Tau_off, Z, dt); switch robot.frictionDatagenModel % Only Coulomb and viscous frictions are linear and can be identified simultaneously with the other parameters. % Nonlinear friction models require state dependant parameter identification case 'no' Tau_friction = Friction(:,1); case 'Viscous' Tau_friction = Friction(:,2); case 'Coulomb' Tau_friction = Friction(:,3); case 'ViscousCoulomb' Tau_friction = Friction(:,4); case 'ViscousCoulombOff' Tau_friction = Friction(:,5); case 'Stribeck' Tau_friction = Friction(:,6); case 'LuGre' Tau_friction = Friction(:,7); otherwise Tau_friction = Friction(:,1); end Z = Friction(:,8); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Robot Real Data Extraction Routine: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [Qd, Qpd, Qppd, Xd, Qm, Xm, Taum] = parseExperimentData(robot, t_sample, augmentedDesiredState, experimentData, options, varargin) % This function parse the file containing the results of the experiments performed on the % real robot. % Variables memory initialization: nbSamples = numel(t_sample); Xm = zeros(3, nbSamples); Xd = zeros(3, nbSamples); Qd = augmentedDesiredState(2*robot.nbDOF+1:end,:); % Desired joint position Qpd = augmentedDesiredState(robot.nbDOF+1:2*robot.nbDOF,:); % Desired joint velocity Qppd = augmentedDesiredState(1:robot.nbDOF,:); % Desired joint acceleration Qm = experimentData.Qm; % Joint position measured with noisy sensor (re-injected in position control loop) Taum = experimentData.Taum; % Control Torque measured with noisy sensor (not re-injected in position control but visible in measured identification data) % Store variables in memory at each sampling epoch: for sampleIndex = 1:nbSamples Hd = feval(sprintf('HT_dh%d_world_%s', robot.nbDOF,robot.name),Qd(:,sampleIndex), robot.numericalParameters.Geometry); Xd(:,sampleIndex) = Hd(1:3,4); % Desired Cartesian Position Hm = feval(sprintf('HT_dh%d_world_%s', robot.nbDOF,robot.name),Qm(:,sampleIndex), robot.numericalParameters.Geometry); Xm(:,sampleIndex) = Hm(1:3,4); % Measured Cartesian Position (with noisy sensor) end end