Subject:
|
Behavior Control, nee Subsumption Architecture
|
Newsgroups:
|
lugnet.robotics.rcx.java
|
Date:
|
Thu, 9 Nov 2000 15:39:36 GMT
|
Viewed:
|
2928 times
|
| |
| |
This post contains a simple implementation of Subsumption Architecture,
which is now called Behavior Control. If you've read my book, you'll
recognize that this code is ported to Java from my NQC and legOS
implementations of Subsumption Architecture. I used this code recently
to demonstrate multithreading to a class I was teaching. It really
helped spice up a dry subject.
The program is for a differential drive robot, e.g. a tank with motors
on outputs A and C. It also responds to a touch sensor (bumper) on input
1. When it bumps into something, it will back up, turn, and move forward
again. In a separate thread (SingBehavior) it sings "Quando men vo" from
La Boheme.
Note the relative simplicity of my main(). You just set the behavior
threads running and let it go.
Thanks again, Jose, for enabling us to program the RCX in Java.
Jonathan
-----
import josx.platform.rcx.*;
import java.util.Random;
public class SubsumptionTest {
public static void main (String[] args) {
Behavior[] behaviors = new Behavior[3];
behaviors[0] = new CruiseBehavior();
behaviors[1] = new BumperBehavior();
behaviors[2] = new SingBehavior();
for (int i = 0; i < behaviors.length; i++)
behaviors[i].start();
Behavior arbitrate = new ArbitrateBehavior(behaviors);
arbitrate.start();
Button.RUN.waitForPressAndRelease();
// Now clean up.
for (int i = 0; i < behaviors.length; i++)
behaviors[i].kill();
arbitrate.kill();
try { Thread.sleep(10); }
catch (InterruptedException ie) {}
Motor.A.stop();
Motor.C.stop();
}
}
-----
public class Behavior
extends Thread {
public static final int kCommandNone = -1;
public static final int kCommandForward = 1;
public static final int kCommandReverse = 2;
public static final int kCommandLeft = 3;
public static final int kCommandRight = 4;
public static final int kCommandStop = 5;
public static final int kCommandFloat = 6;
public int getCommand() { return kCommandNone; }
public void run() {} // For JDK 1.1
public void kill() {}
}
-----
public class CruiseBehavior
extends Behavior {
private boolean mTrucking = true;
private int mCommand = kCommandNone;
public void kill() { mTrucking = false; }
public int getCommand() { return mCommand; }
public void run() {
while (mTrucking) {
mCommand = kCommandForward;
try { Thread.sleep(1000); }
catch (InterruptedException ie) {}
}
}
}
-----
import josx.platform.rcx.*;
import java.util.Random;
public class BumperBehavior
extends Behavior {
private boolean mTrucking = true;
private int mCommand = kCommandNone;
public void kill() { mTrucking = false; }
public int getCommand() { return mCommand; }
public void run() {
while (mTrucking) {
Random random = new Random((int)System.currentTimeMillis());
if (Sensor.S1.readBooleanValue() == true) {
// Back away.
mCommand = kCommandReverse;
try { Thread.sleep(500); }
catch (InterruptedException ie) {}
// Pick a random direction.
if (((int)System.currentTimeMillis()) % 2 == 0) mCommand =
kCommandLeft;
else mCommand = kCommandRight;
// Turn.
int duration = 1000;
try { Thread.sleep(duration); }
catch (InterruptedException ie) {}
// Relinquish control.
mCommand = kCommandNone;
}
}
}
}
-----
import josx.platform.rcx.*;
import java.util.Random;
public class SingBehavior
extends Behavior {
private static final int SIXTH = 12;
private static final int HALF = 3 * SIXTH;
private static final int BEAT = 2 * HALF;
private static final int GRACE = 6;
public void kill() { }
public int getCommand() { return kCommandNone; }
public void run() {
Sound.playTone(330, 2*BEAT);
sleep(2*BEAT + 2*SIXTH);
Sound.playTone(115, SIXTH);
Sound.playTone(208, SIXTH);
Sound.playTone(247, SIXTH);
Sound.playTone(330, SIXTH);
Sound.playTone(311, 2*BEAT);
sleep(4*SIXTH + 2*BEAT + 2*SIXTH);
Sound.playTone(115, SIXTH);
Sound.playTone(208, SIXTH);
Sound.playTone(247, SIXTH);
Sound.playTone(311, SIXTH);
Sound.playTone(277, 3*BEAT);
sleep(4*SIXTH + 3*BEAT + HALF);
Sound.playTone(277, HALF);
Sound.playTone(311, HALF);
Sound.playTone(370, GRACE);
Sound.playTone(330, HALF);
Sound.playTone(311, HALF); sleep (2*HALF);
Sound.playTone(277, HALF);
Sound.playTone(330, HALF);
Sound.playTone(220, HALF);
Sound.playTone(220, 2*BEAT);
sleep(GRACE + 5*HALF + 2*BEAT + HALF);
Sound.playTone(247, HALF);
Sound.playTone(277, HALF);
Sound.playTone(330, GRACE);
Sound.playTone(311, HALF);
Sound.playTone(277, HALF); sleep (2*HALF);
Sound.playTone(247, HALF);
Sound.playTone(311, HALF);
Sound.playTone(208, HALF);
Sound.playTone(208, 2*BEAT);
sleep(GRACE + 5*HALF + 2*BEAT + HALF);
}
public void sleep(int hundreths) {
try { Thread.sleep(hundreths * 10); }
catch (InterruptedException ie) {}
}
}
-----
import josx.platform.rcx.*;
public class ArbitrateBehavior
extends Behavior {
private boolean mTrucking = true;
private int mCommand = kCommandNone;
private Behavior[] mBehaviors;
public ArbitrateBehavior(Behavior[] behaviors) {
mBehaviors = behaviors;
}
public void kill() { mTrucking = false; }
public int getCommand() { return mCommand; }
public void run() {
while (mTrucking) {
for (int i = 0; i < mBehaviors.length; i++) {
int command = mBehaviors[i].getCommand();
if (command != kCommandNone)
mCommand = command;
}
motorControl();
}
}
public void motorControl() {
if (mCommand == kCommandForward) {
Motor.A.forward();
Motor.C.forward();
}
else if (mCommand == kCommandReverse) {
Motor.A.backward();
Motor.C.backward();
}
else if (mCommand == kCommandLeft) {
Motor.A.backward();
Motor.C.forward();
}
else if (mCommand == kCommandRight) {
Motor.A.forward();
Motor.C.backward();
}
else if (mCommand == kCommandStop) {
Motor.A.stop();
Motor.C.stop();
}
else if (mCommand == kCommandFloat) {
Motor.A.flt();
Motor.C.flt();
}
}
}
-----
|
|
1 Message in This Thread:
- Entire Thread on One Page:
- Nested:
All | Brief | Compact | Dots
Linear:
All | Brief | Compact
|
|
|
|