next up previous
Next: 2 絵の表示 Up: 1.8 Subsumption2 サンプル Previous: 1.8 Subsumption2 サンプル

1.8.1 Main.java

全体プログラムは,example/subsumpton2の Main.javaにある.

/**
 * Entry point for the program.
 * This version uses
 * the enhanced Thread interface
 * available in lejos1.0.2
 */
public class Main {
    public static
    void main (String[] arg)
        throws Exception {
        // Won't return until the
        // 'RUN' button is pressed.
        runIt();
    }
          
    /**
     * Return the FSM for
     * wandering around aimlessly
     */
    static Action[] getWanderFSM() {
        Action[] actions = new Action[3];

        actions[0] = new Action() {
                public int act() {
                    Motor.C.setPower(7);
                    Motor.C.forward();
                    Motor.A.setPower(7);
                    Motor.A.forward();
                    return 5000;
                }

                public int nextState() {
                    return 1;
                }
            };
                
        actions[1] = new Action() {
                public int act() {
                    Motor.C.setPower(3);
                    return 2000;
                }

                public int nextState() {
                    return 2;
                }
            };
                
        actions[2] = new Action() {
                public int act() {
                    Motor.C.setPower(7);
                    Motor.C.backward();
                    return 700;
                }

                public int nextState() {
                    return 0;
                }
            };
                
        return actions;
    }

    /**
     * Return the FSM for avoiding
     * obstacles on the left.
     */
    static Action[] getAvoidLeftFSM() {
        Action[] actions = new Action[2];

        actions[0] = new Action() {
                public int act() {
                    Motor.C.setPower(7);
                    Motor.C.backward();
                    Motor.A.setPower(7);
                    Motor.A.backward();
                    return 200;
                }

                public int nextState() {
                    return 1;
                }
            };
                
        actions[1] = new Action() {
                public int act() {
                    Motor.C.forward();
                    return 400;
                }

                public int nextState() {
                    return Action.END;
                }
            };

        return actions;
    }

    /**
     * Return the FSM for avoiding
     * obstacles on the right.
     */
    static Action[] getAvoidRightFSM() {
        Action[] actions = new Action[2];

        actions[0] = new Action() {
                public int act() {
                    Motor.C.setPower(7);
                    Motor.C.backward();
                    Motor.A.setPower(7);
                    Motor.A.backward();
                    return 200;
                }

                public int nextState() {
                    return 1;
                }
            };
                
        actions[1] = new Action() {
                public int act() {
                    Motor.A.forward();
                    return 400;
                }

                public int nextState() {
                    return Action.END;
                }
            };

        return actions;
    }


    /**
     * Build up the behavioural model.
     * Wire the sensors to the actuators.
     * Kick 'em off. Wait until the RUN
     * button is pressed and then return.
     */
    public static void runIt() {
        Sense s1 =
            new SenseNoOwner(new
                Actuator(getWanderFSM()));
        s1.setPri(Thread.MIN_PRIORITY);

        Sense s2 = new
            SenseBumper(Sensor.S3,
                new Actuator(getAvoidLeftFSM()));
        s2.setPri(Thread.MIN_PRIORITY+1);

        Sense s3 = new
            SenseBumper(Sensor.S1,
                new Actuator(getAvoidRightFSM()));
        s3.setPri(Thread.MIN_PRIORITY+1);
        
        Thread.currentThread().
            setPriority(Thread.MAX_PRIORITY);

        s1.runIt();
        s2.runIt();        
        s3.runIt();

        try {
            Button.RUN.waitForPressAndRelease();
        } catch (InterruptedException ie) {
        }
    }
}
Actionインタフェースを定義する.

/**
 * Functor interface. Or, to put it
 * another way, the interface to
 * actions stored in a finite
 * state machine (fsm).
 */
interface Action {
    public static final int END = -1;
    public static final int START = 0;

    /**
     * Perform some sequence of actions.
     */
    public int act();

    /**
     * Return what the next state should be.
     */
    public int nextState();
}
Threadクラスを継承するクラスとして,Actuatorクラスを 設けている.
/**
 * A runnable instance of an FSM,
 */
class Actuator extends Thread {
  // Any old object will do as the 'arbitrator'
  static Object arbitrator = new Object();
        
    // This must be set to the one
    // actuator allowed to execute whilst the
    // monitor of 'arbitrator' is owned.
    static Actuator owner;
        
    protected Action actions[];
    protected int state = Action.END;
        
    // Useful for debugging.        
    public static int tcount = 0;
    public int task;

    /**
     * Constructor. Sets a task id that
     * can be used to identify this instance.
     * Sets the thread daemon flag to true.
     *
     * @param actions an array of Action
     * items to be executed.
     */
    public Actuator(Action[] actions) {
        this.actions = actions;
        task = ++tcount;
        setDaemon(true);
    }
        
    /**
     * The thread entry point.
     * Runs the Actuator's FSM to
     * completion or until
     * it looses ownership.  Wait on
     * the arbitrator's monitor between
     * each state.
     * It might be nice if tasks were
     * left running and just had their access to
     * the actuators gated, but the same
     * effect can be achieved by their just
     * running a worker thread if they need
     * some background processing done.
     * <P>
     * FSM is really a bit of a misnomer as
     * there are no input events so
     * there is only one transition
     * from each state to the next.
     */
    public void run() {
        // Keep running until
        // the program should exit.
        synchronized (arbitrator) {
            do {
     // Wait until we get ownership.
              while (owner != this) {
                try  {
     // Release arbitrator until notified
                    arbitrator.wait();        
                } catch (InterruptedException ie) {
                }
            }
                                
     // Set state to start because
     // we might have been terminated
     // prematurely and we always
     // start from the beginning.
                state = Action.START;
 // Loop until we end or we loose ownership.
                while (owner == this &&
                       state != Action.END) {
                    MinLCD.setNumber(
                        0x301f,
                        (state+1)*10+task,
                        0x3002);
                    MinLCD.refresh();
                    try  {
 // Call wait() because it releases the arbitrator.
                       wait(actions[state].act());
                  } catch (InterruptedException ie) {
                  }
                  state = actions[state].nextState();
              }
     // If we ran to completion signify no owner.
              if (state == Action.END)
                  owner = null;
              arbitrator.notifyAll();        
            } while (true);
        }
    }

    /**
     * Attempt to run this Actuator.
     */        
    public void execute() {
        synchronized (arbitrator) {
            // Basically, set a global flag
            // that all threads can test
            // to see if they should stop
            // running their FSM.
            owner = this;
                        
            // Wake up anything waiting
            // on 'arbitrator'.
            arbitrator.notifyAll();
        }
    }
}
また,Senseクラスは,抽象クラスとして Threadクラスを継承し, SensorListener, SensorConstantsインタフェースを実装 している.

/**
 * Base class for sensor listener thread.
 * This is tightly coupled to
 * an actuator in this implementation.
 * If its sensor listener is called
 * it grabs that sensor's monitor and
 * calls notifuAll(). This should wake
 * up any threads wait()ing on that sensor.
 * <P>
 * Sub-classes should implement run()
 * to wait on the sensor's monitor.
 */
abstract class Sense
    extends Thread
    implements SensorListener, SensorConstants {
    Actuator actuator;
        
    Sense(Actuator actuator) {
        this.actuator = actuator;
        setDaemon(true);
    }

    /**
     * This is actually executed in
     * a thread established by
     * &lt;bumper&gt;.addSensorListener().
     * That thread executes at
     * MAX_PRIORITY so just hand the call off.
     */        
    public void stateChanged(Sensor bumper,
                             int oldValue,
                             int newValue) {
        synchronized (bumper) {
            bumper.notifyAll();
        }
    }
        
    public void setPri(int priority) {
        actuator.setPriority(priority);
        setPriority(priority);
    }
        
    public void runIt() {
        actuator.start();
        start();
    }
}
Senseクラスのサブクラスとして, SenseBumper, SenseNoOwnerクラスなどを定義している.

/**
 * Defines a thread to detect an obstacle
 * on the left. Waits on its bumper
 * and, when notified, will execute its
 * actuator if the bumper's value is true.
 */
class SenseBumper extends Sense {
    Sensor bumper;

    SenseBumper(Sensor bumper,
                Actuator actuator) {
        super(actuator);

        this.bumper = bumper;
        bumper.setTypeAndMode (SENSOR_TYPE_TOUCH,
                               SENSOR_MODE_BOOL);
        bumper.activate();
                
        // Add a listener for the bumper
        bumper.addSensorListener(this);
    }
        
    public void run() {
        // Never exit the thread
        while (true) {
        // Grab the monitor of the bumper
            synchronized (bumper) {
        // While bumper isn't pressed wait.
              do {
                try {
                    bumper.wait();
                } catch (InterruptedException ie) {
                }
                Sound.playTone(440, 10);
              } while (!bumper.readBooleanValue());
            }
            Sound.playTone(500, 10);
                        
            // Execute our FSM
            actuator.execute();
        }
    }
}

/**
 * A class to sense when the arbitrator
 * has no owner so we can give it one.
 * Waits on the arbitrator and when
 * notified checks to see if there is an owner.
 * If not it executes its actuator.
 */
class SenseNoOwner extends Sense  {
    public SenseNoOwner(Actuator actuator) {
        super(actuator);
    }
        
    public void run() {
        while (true) {
            synchronized (Actuator.arbitrator) {
                // If there is no owner, we'll take it.
                if (Actuator.owner == null)
                    actuator.execute();
                try {
                    // Wait until notified
                    Actuator.arbitrator.wait();
                } catch (InterruptedException ie) {
                }
            }        
        }
    }
}


generated through LaTeX2HTML. M.Inaba 平成18年5月7日