View Javadoc

1   package cz.cuni.amis.pogamut.ut2004.agent.navigation.stuckdetector;
2   
3   import java.util.logging.Level;
4   import java.util.logging.Logger;
5   
6   import cz.cuni.amis.pogamut.base.agent.navigation.IStuckDetector;
7   import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
8   import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
9   import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
10  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectListener;
11  import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectUpdatedEvent;
12  import cz.cuni.amis.pogamut.base3d.worldview.object.ILocated;
13  import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
14  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.EndMessage;
15  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Self;
16  
17  /**
18   * Simple {@link IStuckDetector} that watches whether the bot moves at all.
19   * <p>
20   * <p>
21   * You may define a period of time (timeout) in which the bot should move on,
22   * i.e., if the bot won't move a bit in a specified amount of time, it will
23   * report a stuck.
24   * 
25   * @author Jimmy, knight
26   */
27  public class UT2004TimeStuckDetector implements IStuckDetector {
28  
29  	/**
30  	 * Default distance that is regarded as "bot did not move a bit".
31  	 */
32  	private static final double NO_MOVEMENT_SIZE = 10;
33  
34  	/**
35  	 * Default timeout after which the detector reports stuck if the bot did not
36  	 * move. In miliseconds!
37  	 */
38  	private static int DEFAULT_TIMEOUT = 3000;
39  
40  	/**
41  	 * Default timeout when the bot is waiting for something... In milliseconds!
42  	 */
43  	private static int DEFAULT_WAITING_TIMEOUT = 10000;
44  
45  	/**
46  	 * Owner of the detector.
47  	 */
48  	private UT2004Bot bot;
49  
50  	/**
51  	 * Timeout used by the detector, when the bot is not waiting, initialized in
52  	 * the constructor.
53  	 */
54  	private double timeout;
55  
56  	/**
57  	 * Timeout used by the detector when the bot is waiting, initialized in the
58  	 * constructor.
59  	 */
60  	private double waitingTimeout;
61  
62  	private boolean botWaiting = false;
63  
64  	/**
65  	 * In reset set to false. In isStuck set to true - indicator if this
66  	 * detector was already queried after reset about bot stucking.
67  	 */
68  	private boolean bWasIsStuckCalled = false;
69  	
70  	/** 
71  	 * Here we store current time of the simulation. 
72  	 */
73  	private long currentTime;
74  
75  	/**
76  	 * Listener watching for the {@link Self} message. Recalls
77  	 * {@link UT2004TimeStuckDetector#eventSelf(IWorldObjectEvent)}.
78  	 * 
79  	 * @author Jimmy
80  	 */
81  	private class SelfListener implements IWorldObjectListener<Self> {
82  
83  		public SelfListener(IWorldView worldView) {
84  			worldView.addObjectListener(Self.class, WorldObjectUpdatedEvent.class, this);
85  		}
86  
87  		@Override
88  		public void notify(IWorldObjectEvent<Self> event) {
89  			eventSelf(event);
90  		}
91  
92  	};
93  	
94  	/**
95  	 * Listener watching for the {@link EndMessage} message. Recalls
96  	 * {@link UT2004TimeStuckDetector#eventEndMessage(EndMessage)}.
97  	 * 
98  	 * @author Jimmy
99  	 */
100 	private class EndListener implements IWorldEventListener<EndMessage> {
101 
102 		public EndListener(IWorldView worldView) {
103 			worldView.addEventListener(EndMessage.class, this);
104 		}
105 
106 		@Override
107 		public void notify(EndMessage event) {
108 			eventEndMessage(event);
109 		}
110 
111 	};
112 
113 	/**
114 	 * Listener that triggers
115 	 * {@link UT2004TimeStuckDetector#eventSelf(IWorldObjectEvent)}.
116 	 */
117 	private SelfListener selfListener;
118 	
119 	/**
120 	 * Listener that triggers
121 	 * {@link UT2004TimeStuckDetector#eventEndMessage(EndMessage)}.
122 	 */
123 	private EndListener endListener;	
124 
125 	/**
126 	 * Last time when the bot has moved (its velocity had been greater than
127 	 * {@link UT2004TimeStuckDetector#NO_MOVEMENT_SIZE}.
128 	 */
129 	private Double lastMovementTime = null;
130 
131 	/**
132 	 * Whether we should report that the bot has stuck.
133 	 */
134 	private boolean stuck = false;
135 	
136 	private boolean enabled;
137 
138 	private Logger log;
139 
140 	public UT2004TimeStuckDetector(UT2004Bot bot) {
141 		this(bot, DEFAULT_TIMEOUT, DEFAULT_WAITING_TIMEOUT);
142 	}
143 
144 	public UT2004TimeStuckDetector(UT2004Bot bot, double timeoutMillis,
145 			double waitingTimeoutMillis) {
146 		if (this.log == null) {
147 			this.log = bot.getLogger().getCategory(
148 					this.getClass().getSimpleName());
149 		}
150 		this.bot = bot;
151 		this.timeout = timeoutMillis;
152 		this.waitingTimeout = waitingTimeoutMillis;
153 		selfListener = new SelfListener(bot.getWorldView());
154 		endListener = new EndListener(bot.getWorldView());
155 	}
156 
157 	public void eventSelf(IWorldObjectEvent<Self> event) {
158 		if (!enabled) return;
159 
160 		// we always update current time
161 		currentTime = event.getObject().getSimTime();
162 		
163 		// if we were not yet querried about stucking, we will simply do nothing!
164 		if (!bWasIsStuckCalled) {
165 			return;
166 		}
167 		
168 		// check whether we are moving at least a bit...
169 		if (event.getObject().getVelocity().size() > NO_MOVEMENT_SIZE || lastMovementTime == null) {
170 			lastMovementTime = (double) event.getObject().getSimTime();
171 		}
172 		
173 	}
174 	
175 	public void eventEndMessage(EndMessage event) {
176 		if (!enabled || lastMovementTime == null) return;
177 
178 		// we always update current time
179 		currentTime = event.getSimTime();
180 		
181 		if (!bWasIsStuckCalled) {
182 			return;
183 		}
184 		if (botWaiting) {
185 			if (currentTime - lastMovementTime >= waitingTimeout) {
186 				stuck = true;
187 				if (log != null && log.isLoggable(Level.WARNING)) log.warning("Bot is WAITING for more than " + waitingTimeout + " ms, considering that it has stuck.");
188 			}
189 		} else {
190 			if (currentTime - lastMovementTime >= timeout) {
191 				stuck = true;
192 				if (log != null && log.isLoggable(Level.WARNING)) log.warning("Bot should be moving but it is standing still for more than " + timeout + " ms, considering that it has stuck.");
193 			}
194 		}
195 	}
196 	
197 	@Override
198 	public void setEnabled(boolean state) {
199 		if (this.enabled == state) return;
200 		this.enabled = state;		
201 	}
202 
203 	@Override
204 	public void setBotWaiting(boolean state) {
205 		botWaiting = state;
206 		lastMovementTime = null;
207 	}
208 
209 	@Override
210 	public boolean isStuck() {
211 		if (!bWasIsStuckCalled) {
212 			// isStuck called for the first time after reset - we return false
213 			// and we reset lastMovementTime
214 			lastMovementTime = (double) currentTime;
215 			bWasIsStuckCalled = true;
216 			return false;
217 		}
218 		
219 		return stuck;
220 	}
221 
222 	@Override
223 	public void reset() {
224 		if (log != null && log.isLoggable(Level.FINER)) log.finer("Reset.");
225 		lastMovementTime = Double.NEGATIVE_INFINITY;
226 		bWasIsStuckCalled = false;
227 		stuck = false;
228 	}
229 
230 	@Override
231 	public void setBotTarget(ILocated target) {
232 		// WE DO NOT CARE
233 	}
234 
235 }