Project: bml_realizer License: BSD Dependencies:
Used by:
None |
bml_realizer/src/edu/wpi/hri/bml/realizer/Schedule.javaGo to the documentation of this file.00001 /* 00002 * Software License Agreement (BSD License) 00003 * 00004 * Copyright (c) 2010, Worcester Polytechnic Institute 00005 * All rights reserved. 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions 00009 * are met: 00010 * 00011 * * Redistributions of source code must retain the above copyright 00012 * notice, this list of conditions and the following disclaimer. 00013 * * Redistributions in binary form must reproduce the above 00014 * copyright notice, this list of conditions and the following 00015 * disclaimer in the documentation and/or other materials provided 00016 * with the distribution. 00017 * * Neither the name of Worcester Polytechnic Institute. nor the names 00018 * of its contributors may be used to endorse or promote products 00019 * derived from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00022 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00023 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00024 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00025 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00026 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00027 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00028 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00029 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00030 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00031 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 * POSSIBILITY OF SUCH DAMAGE. 00033 */ 00034 package edu.wpi.hri.bml.realizer; 00035 00036 import java.util.ArrayList; 00037 import java.util.Hashtable; 00038 import java.util.List; 00039 00040 import edu.wpi.hri.bml.behavior.Behavior; 00041 import edu.wpi.hri.bml.behavior.BehaviorList; 00042 import edu.wpi.hri.bml.behavior.ConstraintBehavior; 00043 import edu.wpi.hri.bml.behavior.EmitBehavior; 00044 import edu.wpi.hri.bml.behavior.FaceBehavior; 00045 import edu.wpi.hri.bml.behavior.GazeBehavior; 00046 import edu.wpi.hri.bml.behavior.GestureBehavior; 00047 import edu.wpi.hri.bml.behavior.HeadBehavior; 00048 import edu.wpi.hri.bml.behavior.LipsBehavior; 00049 import edu.wpi.hri.bml.behavior.LocomotionBehavior; 00050 import edu.wpi.hri.bml.behavior.SpeechBehavior; 00051 import edu.wpi.hri.bml.behavior.SyncRef; 00052 import edu.wpi.hri.bml.behavior.ConstraintBehavior.SyncBlock; 00053 import edu.wpi.hri.bml.behavior.SyncRef.SyncPoint; 00054 import edu.wpi.hri.bml.exec.EmitExecutor; 00055 import edu.wpi.hri.bml.exec.Executor; 00056 import edu.wpi.hri.bml.exec.FaceExecutor; 00057 import edu.wpi.hri.bml.exec.GazeExecutor; 00058 import edu.wpi.hri.bml.exec.GestureExecutor; 00059 import edu.wpi.hri.bml.exec.HeadExecutor; 00060 import edu.wpi.hri.bml.exec.LipsExecutor; 00061 import edu.wpi.hri.bml.exec.ListExecutor; 00062 import edu.wpi.hri.bml.exec.LocomotionExecutor; 00063 import edu.wpi.hri.bml.exec.SchedulerException; 00064 import edu.wpi.hri.bml.exec.SpeechExecutor; 00065 import edu.wpi.hri.bml.net.BMLPetriNet; 00066 import edu.wpi.hri.log.Logger; 00067 import edu.wpi.hri.log.Logger.Colors; 00068 import edu.wpi.hri.log.Logger.LoggerLevel; 00069 00078 public class Schedule { 00079 00080 private final List<Executor> toStart; 00081 private final BehaviorList behaviors; 00082 private final Hashtable<String, Executor> execs; 00083 private final ListExecutor fullExecutor; 00084 private final Logger logger; 00085 private final BMLComm comm; 00086 private final BMLPetriNet petrinet; 00087 00101 public Schedule(Logger logger, BehaviorList list, BMLComm comm, 00102 ControlComm control) { 00103 this.toStart = new ArrayList<Executor>(); 00104 this.behaviors = list; 00105 this.execs = new Hashtable<String, Executor>(list.size() * 2); 00106 this.logger = logger.sub(Colors.SCHEDULE, "SCHED"); 00107 this.comm = comm; 00108 00109 // first we need to add in all of the behaviors by the executor 00110 this.logger.debug(LoggerLevel.SCHEDULE, 00111 "Generating executors from behaviors"); 00112 this.fullExecutor = new ListExecutor(logger, comm, list); 00113 this.petrinet = new BMLPetriNet(fullExecutor, logger); 00114 this.createExecutors(logger, control); 00115 00116 this.toStart.addAll(execs.values()); 00117 this.execs.put(this.fullExecutor.getID(), this.fullExecutor); 00118 00119 this.logger.debug(LoggerLevel.ALWAYS, "Created scheduler ..."); 00120 } 00121 00127 private void createExecutors(Logger base, ControlComm control) { 00128 for (EmitBehavior emit : behaviors.getEmits()) 00129 this.execs.put(emit.getID(), new EmitExecutor(base, comm, emit)); 00130 00131 for (FaceBehavior face : behaviors.getFaces()) 00132 this.execs.put(face.getID(), new FaceExecutor(base, comm, control, 00133 face)); 00134 00135 for (GazeBehavior gaze : behaviors.getGazes()) 00136 this.execs.put(gaze.getID(), new GazeExecutor(base, comm, control, 00137 gaze)); 00138 00139 for (GestureBehavior gesture : behaviors.getGestures()) 00140 this.execs.put(gesture.getID(), new GestureExecutor(base, comm, 00141 control, gesture)); 00142 00143 for (HeadBehavior head : behaviors.getHeads()) 00144 this.execs.put(head.getID(), new HeadExecutor(base, comm, control, 00145 head)); 00146 00147 for (LipsBehavior lips : behaviors.getLips()) 00148 this.execs.put(lips.getID(), new LipsExecutor(base, comm, control, 00149 lips)); 00150 00151 for (LocomotionBehavior locomotion : behaviors.getLocomotions()) 00152 this.execs.put(locomotion.getID(), new LocomotionExecutor(base, 00153 comm, control, locomotion)); 00154 00155 for (SpeechBehavior speech : behaviors.getSpeeches()) 00156 this.execs.put(speech.getID(), new SpeechExecutor(base, comm, 00157 control, speech)); 00158 00159 for (String id : execs.keySet()) 00160 petrinet.addExecutor(execs.get(id)); 00161 } 00162 00173 private void concatBehaviors(List<Behavior> behavs) 00174 throws SchedulerException { 00175 if (behavs.size() > 0) { 00176 00177 for (int index = 1; index < behavs.size(); index++) { 00178 Behavior curr = behavs.get(index); 00179 Executor exec = this.execs.get(curr.getID()); 00180 00181 if (toStart.contains(exec)) { 00182 Behavior prev = behavs.get(index - 1); 00183 petrinet.before(prev.getID() + SyncPoint.END, curr.getID() 00184 + SyncPoint.START); 00185 } 00186 } 00187 } 00188 } 00189 00190 private void genExcept(String reason, SyncRef base, SyncRef listening, 00191 boolean required) throws SchedulerException { 00192 SchedulerException e = new SchedulerException(reason, base, listening, 00193 !required); 00194 if (e.warning) 00195 this.comm.publishException(e); 00196 else 00197 throw e; 00198 } 00199 00200 private void addConstraints(ConstraintBehavior constraint) 00201 throws SchedulerException { 00202 this.logger.debug(LoggerLevel.SCHEDULE, "Executing Constraints for " 00203 + constraint.getID()); 00204 // for each standard constraint (at the same time): 00205 for (SyncBlock block : constraint.getSynchronize()) { 00206 boolean isStarted = false; 00207 // set the block refs to listen for the original start ref 00208 for (SyncRef sync : block.getRefs()) { 00209 logger.debug(LoggerLevel.SCHEDULE, "Synchronizing " 00210 + block.getStartRef() + " to " + sync); 00211 double offset = block.getStartRef().getOffset() 00212 - sync.getOffset(); 00213 if (offset != 0) { 00214 genExcept("Can not apply offset to synchronize, use after", 00215 block.getStartRef(), sync, constraint.isRequired()); 00216 00217 if (!petrinet.after(sync.getID() + ":" + sync.getPoint(), 00218 block.getStartRef().getID() + ":" 00219 + block.getStartRef().getPoint(), 00220 (long) (offset * 1000))) { 00221 genExcept("Could not add after instead of synchronize", 00222 block.getStartRef(), sync, constraint 00223 .isRequired()); 00224 } 00225 } else if (!petrinet.synchronize( 00226 block.getStartRef().toString(), sync.toString())) { 00227 genExcept("Could not synchronize ", block.getStartRef(), 00228 sync, constraint.isRequired()); 00229 } 00230 if (sync.getPoint() == SyncPoint.START) 00231 this.toStart.remove(execs.get(sync.getID())); 00232 else 00233 isStarted = true; 00234 } 00235 if ((block.getStartRef().getPoint() == SyncPoint.START) 00236 && isStarted) 00237 this.toStart.remove(execs.get(block.getStartRef().getID())); 00238 } 00239 00240 // then for each before block 00241 for (SyncBlock block : constraint.getBefore()) { 00242 // set the base to occur after the sync points in the block 00243 for (SyncRef sync : block.getRefs()) { 00244 logger.debug(LoggerLevel.SCHEDULE, "Before " 00245 + block.getStartRef() + " comes " + sync); 00246 double offset = block.getStartRef().getOffset() 00247 - sync.getOffset(); 00248 if (!petrinet.before(block.getStartRef().getID() + ":" 00249 + block.getStartRef().getPoint(), sync.getID() + ":" 00250 + sync.getPoint(), (long) (offset * 1000))) { 00251 genExcept("Could not add after constraint", block 00252 .getStartRef(), sync, constraint.isRequired()); 00253 } 00254 } 00255 if (block.getStartRef().getPoint() == SyncPoint.START) 00256 this.toStart.remove(execs.get(block.getStartRef().getID())); 00257 } 00258 00259 // and finally for each after block 00260 for (SyncBlock block : constraint.getAfter()) { 00261 // set the block sync points to occur after the base point 00262 for (SyncRef sync : block.getRefs()) { 00263 logger.debug(LoggerLevel.SCHEDULE, "After " 00264 + block.getStartRef() + " comes " + sync); 00265 double offset = block.getStartRef().getOffset() 00266 - sync.getOffset(); 00267 if (!petrinet.after(block.getStartRef().getID() + ":" 00268 + block.getStartRef().getPoint(), sync.getID() + ":" 00269 + sync.getPoint(), (long) (offset * 1000))) { 00270 genExcept("Could not add after constraint", block 00271 .getStartRef(), sync, constraint.isRequired()); 00272 } 00273 if (sync.getPoint() == SyncPoint.START) 00274 this.toStart.remove(execs.get(sync.getID())); 00275 } 00276 } 00277 } 00278 00289 public void schedule() throws SchedulerException { 00290 this.logger.debug(LoggerLevel.ALWAYS, "Calculating schedule"); 00291 00292 // start with the constraints 00293 this.addConstraints(behaviors.getRequiredConstraints()); 00294 this.addConstraints(behaviors.getOptionalConstraints()); 00295 00296 this.logger.debug(LoggerLevel.ALWAYS, 00297 "Constraints satisfied, scheduling all other sync points"); 00298 00299 // have all of the emit behaviors fire off of something else. 00300 for (EmitBehavior emit : behaviors.getEmits()) { 00301 if (!petrinet.synchronize(emit.getSource().getID() + ":" 00302 + emit.getSource().getPoint(), emit.getID() + ":" 00303 + SyncPoint.START)) { 00304 genExcept("Could not start emit behavior", emit.getSource(), 00305 new SyncRef(emit, SyncPoint.START, 0), emit 00306 .isRequired()); 00307 } 00308 } 00309 00310 // then find the start and end points of each behavior to sync to 00311 for (Behavior behav : behaviors) { 00312 if (behav.getStart() != null) { 00313 SyncRef start = behav.getStart(); 00314 if (!petrinet.synchronize(start.getID() + ":" 00315 + start.getPoint(), behav.getID() + ":" 00316 + SyncPoint.START)) { 00317 genExcept("Could not start behavior", start, new SyncRef( 00318 behav, SyncPoint.START, 0), behav.isRequired()); 00319 } 00320 } 00321 00322 if (behav.getEnd() != null) { 00323 SyncRef end = behav.getEnd(); 00324 if (!petrinet.synchronize(end.getID() + ":" + end.getPoint(), 00325 behav.getID() + ":" + SyncPoint.END)) { 00326 genExcept("Could not end behavior", end, new SyncRef(behav, 00327 SyncPoint.END, 0), behav.isRequired()); 00328 } 00329 } 00330 } 00331 00332 // append behaviors to previous of same type, if not scheduled, in order 00333 // to ensure that each behavior is indeed started 00334 this.concatBehaviors(new ArrayList<Behavior>(behaviors.getFaces())); 00335 this.concatBehaviors(new ArrayList<Behavior>(behaviors.getGazes())); 00336 this.concatBehaviors(new ArrayList<Behavior>(behaviors.getGestures())); 00337 this.concatBehaviors(new ArrayList<Behavior>(behaviors.getHeads())); 00338 this.concatBehaviors(new ArrayList<Behavior>(behaviors.getLips())); 00339 this 00340 .concatBehaviors(new ArrayList<Behavior>(behaviors 00341 .getLocomotions())); 00342 this.concatBehaviors(new ArrayList<Behavior>(behaviors.getSpeeches())); 00343 00344 if (petrinet.existsCycle()) 00345 throw new SchedulerException("Schedule created a cycle", null, 00346 null, false); 00347 } 00348 00354 public byte execute() { 00355 this.logger.debug(LoggerLevel.ALWAYS, "Executing schedule"); 00356 byte success = petrinet.execute(); 00357 00358 for (Executor executor : this.execs.values()) { 00359 this.logger.debug(LoggerLevel.BML_EXECUTION, "finishing " 00360 + executor.getID()); 00361 this.behaviors.addFinished(executor.getID(), executor.getPoint(), 00362 executor.getResult()); 00363 } 00364 00365 this.logger.debug(LoggerLevel.ALWAYS, "BML execution completed [" 00366 + success + "]"); 00367 return success; 00368 } 00369 } |