/** * */ package jp.ac.fit.asura.nao; import java.util.ArrayList; import java.util.List; import jp.ac.fit.asura.nao.AsuraCore.Controller; import jp.ac.fit.asura.nao.misc.FrameException; import org.apache.log4j.Logger; /** * シングルスレッドのAsuraCoreコントローラ. 主にWebots用. * * @author sey * */ public class SingleThreadController extends Controller { private static final Logger log = Logger .getLogger(SingleThreadController.class); public SingleThreadController(RobotContext robotContext) { this.robotContext = robotContext; this.effector = robotContext.getEffector(); this.sensor = robotContext.getSensor(); this.camera = robotContext.getCamera(); singleGroup = new ArrayList<RobotLifecycle>(); singleGroup.add(robotContext.getCommunication()); singleGroup.add(robotContext.getSensoryCortex()); singleGroup.add(robotContext.getVision()); singleGroup.add(robotContext.getLocalization()); singleGroup.add(robotContext.getStrategy()); singleGroup.add(robotContext.getMotor()); singleGroup.add(robotContext.getGlue()); Runnable task = new SingleRunnable(); thread = new Thread(null, task, "SingleThread"); } private class SingleRunnable implements Runnable { private final Logger log = Logger.getLogger(SingleRunnable.class); @Override public void run() { log.info("Start SingleThread"); try { VisualFrameContext context = new VisualFrameContext( robotContext); MotionFrameContext motionFrame = new MotionFrameContext( robotContext); int frame = 0; Image image = camera.createImage(); long lastImageTime = 0; while (isActive) { long before = System.currentTimeMillis(); context.setFrame(frame); effector.before(); sensor.before(); log.trace("polling sensor."); sensor.poll(); motionFrame.setActive(true); sensor.update(motionFrame.getSensorContext()); motionFrame.setFrame(frame); if (log.isTraceEnabled()) log.trace(String.format("step frame %d at %d ms", context.getFrame(), context.getTime())); camera.before(); log.debug("Step frame " + frame); camera.updateImage(image); context.setImage(image); try { long imageTime = image.getTimestamp(); long timeDiff = imageTime - lastImageTime; lastImageTime = imageTime; if (log.isTraceEnabled()) log.trace("image updated. time:" + imageTime + " [" + timeDiff + " ms]"); if (timeDiff < 0) throw new FrameException("Past image received:" + timeDiff); motionFrame.setInUse(true); context.setMotionFrame(motionFrame); for (RobotLifecycle cycle : singleGroup) { if (log.isTraceEnabled()) log.trace("call step " + cycle.toString()); if (cycle instanceof VisualCycle) ((VisualCycle) cycle).step(context); else if (cycle instanceof MotionCycle) ((MotionCycle) cycle).step(motionFrame); else assert false; } } catch (FrameException e) { log.warn("frame " + context.getFrame(), e); } image.dispose(); motionFrame.setInUse(false); motionFrame.setActive(false); camera.after(); sensor.after(); effector.after(); long after = System.currentTimeMillis(); if (targetVisualCycleTime == 0) { Thread.yield(); } else { long wait = Math.max(targetVisualCycleTime - (after - before), 0); if (log.isTraceEnabled()) log.trace("wait " + wait + "[ms] (cunsumed " + (after - before) + " [ms])"); Thread.sleep(wait); } if (log.isDebugEnabled()) { Runtime rt = Runtime.getRuntime(); log.debug("Free memory:" + rt.freeMemory() / 1024); } frame++; } } catch (Exception e) { log.fatal("SingleThread is dead with exception.", e); } log.info("SingleThread stopped."); } } private RobotContext robotContext; private Effector effector; private Camera camera; private Sensor sensor; private List<RobotLifecycle> singleGroup; private Thread thread; // Visionの目標動作サイクルをmsで指定. private long targetVisualCycleTime; private boolean isActive; private boolean stopExceptionOccurs = false; @Override public void init() throws Exception { for (RobotLifecycle rl : singleGroup) { log.debug("init " + rl.toString()); rl.init(robotContext); } } @Override public void start() throws Exception { for (RobotLifecycle rl : singleGroup) { log.debug("start " + rl.toString()); rl.start(); } isActive = true; thread.start(); } @Override public void stop() throws Exception { isActive = false; thread.join(); } public long getTargetVisualCycleTime() { return targetVisualCycleTime; } public void setTargetVisualCycleTime(long targetVisualCycleTime) { this.targetVisualCycleTime = targetVisualCycleTime; } }