SimulationPURPOSESimulates a robot performing Pose SLAM.
SYNOPSISfunction Result=Simulation(F,R,Parameters)
DESCRIPTIONSimulates a robot performing Pose SLAM. This function is also used to continue a previously started simulation. Parameters: F: the P_Filter to use to estimate the trajectory of the robot. R: The robot to use in the simulation Parameters.maxSteps: Number of steps to run the simulation. Set to 0 to use as many steps as sensor readings available. This parameter and the use of this function as well as ContinueSimulation allow to run a full simulation in separate phases. The first step is the initial estimation. So use at maxSteps 2 to perform one filter step and so on. Parameters.plot: true if the trajectory as estimated by the filter has to be plotted while simulating. Parameters.plotSensors: Array of booleans indicating which sensors are to be plotted along with the filter information. Right now only RealVison and RealLaser sensors have non-void Plot functions. In the first case the images of the cameras are shown at the right of the trajectory and in the second case the laser readings are plotted at the corresponding pose. Parameters.Domain: Area where the robot is expected to move. Used to define the tree of poses and the axis of the plot. Parameters.loopClosure: Selects the method to determine the loop closure points. The rest of parametres depend on the 'loopClosure' value For 'NoLoops' or 'AllLoos' no more parameters are needed. For 'DetectLoops'or 'TreeDetectLoops' we have to provide - Parameters.matchArea: Area arround a pose where it is likely to get similar sensor readings (sensor readings that can be registered to the sensor readings of the current pose). This is 'v_r' in the paper. Todo: integrate this threshold in the sensor information. - Parameters.loopNoise: Typical noise of the sensors closing loops. The sensors that will be used to register poses. This is \bar{\Sigma_y} in the paper. - Parameters.pdRange: An interval [p1,p2]. If a pose has a probability higher p1 of being in the match area of the current robot's pose it is considered for a loop (if the information test below agrees to do so). If the pose has probability higher than p2 of being in the match area of the current robot's pose the current pose is considered for removal (see information test below) This is 's' in the paper. However here we allow to define two values for it. - Parameters.igRange: An interval [ig1,ig2]. If the information gain of apossible loop closure (suggested by the distance criterion) is above ig2 the loops closure is considered informativeenough. If the information gain is below ig1, the current robot pose is considered redundant (it can be removed since there is a very similar pose already in the trajectory). The information criterion is only considered after the distance one. This is 'g' in the paper. However we allow to define two values for it. Outputs: Results: A structure with the Filter, the Robot, the Parameters and some outputs (time, inf. gain,...) CROSS-REFERENCE INFORMATIONThis function calls:
SOURCE CODE0001 function Result=Simulation(F,R,Parameters) 0002 % Simulates a robot performing Pose SLAM. 0003 % This function is also used to continue a previously started simulation. 0004 % 0005 % Parameters: 0006 % F: the P_Filter to use to estimate the trajectory of the robot. 0007 % R: The robot to use in the simulation 0008 % Parameters.maxSteps: Number of steps to run the simulation. 0009 % Set to 0 to use as many steps as sensor readings available. 0010 % This parameter and the use of this function as well as 0011 % ContinueSimulation allow to run a full simulation in 0012 % separate phases. 0013 % The first step is the initial estimation. So use at maxSteps 0014 % 2 to perform one filter step and so on. 0015 % Parameters.plot: true if the trajectory as estimated by the filter 0016 % has to be plotted while simulating. 0017 % Parameters.plotSensors: Array of booleans indicating which sensors 0018 % are to be plotted along with the filter information. 0019 % Right now only RealVison and RealLaser sensors have 0020 % non-void Plot functions. In the first case the images 0021 % of the cameras are shown at the right of the 0022 % trajectory and in the second case the laser readings 0023 % are plotted at the corresponding pose. 0024 % Parameters.Domain: Area where the robot is expected to move. Used 0025 % to define the tree of poses and the axis of the plot. 0026 % Parameters.loopClosure: Selects the method to determine the loop 0027 % closure points. 0028 % The rest of parametres depend on the 'loopClosure' value 0029 % For 'NoLoops' or 'AllLoos' no more parameters are needed. 0030 % For 'DetectLoops'or 'TreeDetectLoops' we have to provide 0031 % - Parameters.matchArea: Area arround a pose where it is likely 0032 % to get similar sensor readings (sensor readings that can be 0033 % registered to the sensor readings of the current pose). 0034 % This is 'v_r' in the paper. 0035 % Todo: integrate this threshold in the sensor information. 0036 % - Parameters.loopNoise: Typical noise of the sensors closing 0037 % loops. The sensors that will be used to register poses. 0038 % This is \bar{\Sigma_y} in the paper. 0039 % - Parameters.pdRange: An interval [p1,p2]. If a pose has a 0040 % probability higher p1 of being in the match area of the 0041 % current robot's pose it is considered for a loop (if the 0042 % information test below agrees to do so). If the pose has 0043 % probability higher than p2 of being in the match area of the 0044 % current robot's pose the current pose is considered for 0045 % removal (see information test below) 0046 % This is 's' in the paper. However here we allow to define two 0047 % values for it. 0048 % - Parameters.igRange: An interval [ig1,ig2]. If the information 0049 % gain of apossible loop closure (suggested by the distance 0050 % criterion) is above ig2 the loops closure is considered 0051 % informativeenough. If the information gain is below ig1, the 0052 % current robot pose is considered redundant (it can be removed 0053 % since there is a very similar pose already in the trajectory). 0054 % The information criterion is only considered after the 0055 % distance one. 0056 % This is 'g' in the paper. However we allow to define two 0057 % values for it. 0058 % 0059 % Outputs: 0060 % Results: A structure with the Filter, the Robot, the Parameters and 0061 % some outputs (time, inf. gain,...) 0062 0063 if ~Parameters.quiet 0064 fprintf('Simulating: \n'); 0065 end 0066 0067 % Robot's number of sensors 0068 Sensors=get(R,'sensors'); 0069 numSensors=size(Sensors,2); 0070 0071 pt=InitFilterPlot(F,Parameters); 0072 0073 % Default output is a tree from the filter data (non-empty if we 0074 % are continuing a previously stopped simulation). 0075 if strcmp(Parameters.loopClosure,'TreeDetectLoops') 0076 pd=GetPoseData(F); 0077 T=BTree({pd{1:(end-1)}}); 0078 else 0079 T=0; 0080 end 0081 0082 % sometimes, when detecting possible points for loop closure we 0083 % detect that current pose is redundant (i.e., we already have 0084 % a nearby pose in the filter). If so, next pose to be added 0085 % replaces the current one. This helps to control the size 0086 % of the filter. 0087 redundantPose=false; 0088 0089 % To gather estatistics about the loop closure 0090 NPL=0; % number of proposed loops 0091 NCL=0; % number of actually closed loops 0092 0093 % To gather statistics about execution time 0094 timeSA=0; % Time used in state augmentation (Update) 0095 timeLC=0; % Time used in loop closure (UpdateLoop) 0096 timeS=0; % Time used searching for neighbours 0097 timeT=0; % Time used inserting in the tree and re-building it 0098 0099 totalIG=0; % total information gain of actually closed loops 0100 0101 % To comptute the filter consitency (only when grount truth is 0102 % available). 0103 groundTruthAvailable=isfield(Parameters,'groundTruth'); 0104 NEES=[]; 0105 0106 % continue from last step 0107 step=get(F,'nSteps'); 0108 0109 done=false; 0110 0111 while ~done 0112 0113 step=step+1; 0114 0115 if Parameters.maxSteps>0 0116 done=(step>=Parameters.maxSteps); 0117 end 0118 0119 if ~done 0120 % And now iterate reading the sensors and updating the filter 0121 % done is set to true when no more sensor readings are available 0122 [done R]=MoveRobot(R); % returns done=false whe no more sensor readings 0123 end 0124 0125 if ~done 0126 0127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0128 % Update the filter with the new sensor readings -> add a new state 0129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0130 [SR Sn]=GetOdometry(R); 0131 0132 ck=cputime; 0133 F=Update(F,step,SR,Sn,redundantPose); 0134 timeSA(step)=(cputime-ck); 0135 0136 if Parameters.plot 0137 if redundantPose 0138 pt=PlotFilter(F,Parameters); 0139 else 0140 pt=UpdateFilterPlot(F,step,pt,true); 0141 end 0142 end 0143 0144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0145 % Use the filter information to detect possible points for loop 0146 % closuse (i.e., if the current pose is close enough) 0147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0148 switch Parameters.loopClosure 0149 case 'NoLoops' 0150 L=NoLoops(F); 0151 0152 case 'AllLoops' 0153 L=AllLoops(F); 0154 0155 case 'DetectLoops' 0156 ck=cputime; 0157 L=DetectLoops(F,Parameters.matchArea,Parameters.pdRange); 0158 timeS(step)=(cputime-ck); 0159 0160 case 'TreeDetectLoops' 0161 if step>1 0162 pd=GetPoseData(F,step-1); 0163 if isa(pd,'PoseData') 0164 % if 'step' is not one of the removed steps 0165 ck=cputime; 0166 T=InsertInTree(T,pd); 0167 timeT(step)=(cputime-ck); 0168 end 0169 end 0170 ck=cputime; 0171 L=TreeDetectLoops(F,T,Parameters.matchArea,Parameters.pdRange); 0172 timeS(step)=(cputime-ck); 0173 otherwise 0174 error('Unknow loop closure procedure'); 0175 end 0176 0177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0178 % Check if at least one of the sensors confirm the loop closure 0179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0180 n=size(L,2); 0181 0182 NPL=NPL+n; % number of tentative loop closures 0183 0184 redundantPose=false; 0185 0186 ncl=0; % number of closed loops in this time slice 0187 0188 % Compute the information gain for all the tentative links 0189 allI=cellfun(@(n)(InformationGain(F,Parameters.noiseLoopClosure,n.step)),L); 0190 0191 while n>0 0192 0193 % select the maximally informative link. 0194 [I mi]=max(allI); 0195 link=L{mi}; 0196 cl=false; % the loop is not closed so far 0197 0198 % link to the neighbouring pose 0199 ShowLinkToNeighbour(F,Parameters,pt,step,link.step,'y'); 0200 0201 if (I>Parameters.igRange(2)) && ~PreviousPose(F,link.step) 0202 0203 % link to the neighbouring informative pose 0204 ShowLinkToNeighbour(F,Parameters,pt,step,link.step,'b'); 0205 0206 % Look for the sensor that confirm the loop closure link 0207 j=1; 0208 nSLC=0; % Number of sensors that confirm the loop closure 0209 0210 while (j<=numSensors) && (I>Parameters.igRange(2)) 0211 [c d Sn]=SensorLoopCloses(get(R,'sensor',j),link.step,step); 0212 0213 if c 0214 % If the sensor confirms the loop 0215 % we compute the true information gain 0216 Is=InformationGain(F,Sn,link.step); 0217 I=min(I,Is); 0218 0219 if Is>Parameters.igRange(2) 0220 % This sensor confirms the loop and it is truly 0221 % informative: Store the link data (link mean and noise) 0222 % according to this sensor 0223 nSLC=nSLC+1; 0224 dSLC{nSLC}=d; 0225 sSLC{nSLC}=Sn; 0226 end 0227 end 0228 j=j+1; 0229 end 0230 0231 % if at least one sensor confirms the infomrative link 0232 if nSLC>0 0233 cl=true; % the link is actually confirmed and the loop closed 0234 0235 % if at least one sensor confirms the loop closure, execute it. 0236 ck=cputime; 0237 F=UpdateLoop(F,link.step,dSLC,sSLC); 0238 timeLC(step)=(cputime-ck); 0239 0240 ncl=ncl+1; 0241 0242 totalIG=totalIG+I; 0243 0244 if ~Parameters.quiet 0245 fprintf(' Loop closure: [%u %u] ig:%f pd:%f -> ',link.step,step,I,link.pd); 0246 display(dSLC{1}); 0247 end 0248 0249 if Parameters.plot 0250 % Replot the filter after the loop closure 0251 pt=PlotFilter(F,Parameters); 0252 end 0253 end 0254 end % information is large enough 0255 0256 % If the pose is close to another pose and the change in the map when 0257 % linking the two poses is small -> the current pose is redundant 0258 if (link.pd>Parameters.pdRange(2)) && (I<Parameters.igRange(1)) 0259 redundantPose=true; 0260 end 0261 0262 L(mi)=[]; % Removes element mi from L 0263 0264 if cl 0265 % If the link resulted in a loop we have to recompute the 0266 % information gain 0267 allI=cellfun(@(n)(InformationGain(F,Parameters.noiseLoopClosure,n.step)),L); 0268 else 0269 allI(mi)=[]; % Removes element mi from allI 0270 end 0271 0272 n=size(L,2); % n=n-1 0273 0274 end % while n>0 0275 0276 if ncl>0 0277 redundantPose=false; 0278 if strcmp(Parameters.loopClosure,'TreeDetectLoops') 0279 % If we closed a loop, we have to update the tree 0280 pd=GetPoseData(F); 0281 ck=cputime; 0282 T=UpdateTree(T,F,pd); 0283 timeT(step)=(cputime-ck); 0284 end 0285 end 0286 0287 NCL=NCL+ncl; %number of loops actually closed 0288 0289 if groundTruthAvailable 0290 NEES(step)=ComputeNEES(F,Parameters.groundTruth); 0291 end 0292 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0293 0294 pt=HideLinkToNeighbour(Parameters,pt); 0295 0296 end % if ~done 0297 0298 end % while 0299 0300 Result.Filter=F; % Filter at the end of the simulation 0301 Result.Robot=R; % Robot used in the simulation 0302 Result.Tree=T; % Tree used for data association, possibly empty 0303 Result.Parameters=Parameters; % Parameters used in the simulation 0304 0305 Result.timeS=timeS; % Seach time during data association 0306 Result.timeT=timeT; % Time used building and updating the tree 0307 Result.timeSA=timeSA; % Time used in state augmentation (one value per iteration) 0308 Result.timeLC=timeLC; % Time used in loop closure (one value per iteration) 0309 Result.timeF=sum(timeSA)+sum(timeLC); % Total time used in filter operations 0310 Result.time=Result.timeF+sum(Result.timeS)+sum(Result.timeT); % Total time used in the simulation 0311 Result.numClosedLoops=NCL; % Number of closed loops 0312 Result.numProposedLoops=NPL; % Number of proposed loops 0313 0314 Result.totalIG=totalIG; % Sum of the information gain for all loops 0315 Result.NEES=NEES; % NEES per iteration 0316 0317 if ~Parameters.quiet 0318 fprintf('\nSimulation done:\n'); 0319 fprintf(' Execution time: %f s (%f s per step)\n',Result.time,Result.time/step); 0320 fprintf(' NN search time : %f\n',sum(Result.timeS)); 0321 if strcmp(Parameters.loopClosure,'TreeDetectLoops') 0322 fprintf(' Tree update time : %f\n',sum(Result.timeT)); 0323 end 0324 fprintf(' State Augmenation time: %f\n',sum(Result.timeSA)); 0325 fprintf(' Loop Closure time : %f\n',sum(Result.timeLC)); 0326 if Result.numProposedLoops>0 0327 fprintf(' Closed vs. Proposed loops: %u/%u = %.2f %%\n',Result.numClosedLoops,Result.numProposedLoops,Result.numClosedLoops/Result.numProposedLoops*100); 0328 else 0329 fprintf(' No loop closure was proposed\n'); 0330 end 0331 end 0332 |