View Javadoc

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