In reading through you code, it's obvious that you had a lot of trial and error. What it looks like you tried to do was make HitWall act as a Cancel class as well. The problem is that there are two instances of HitWall and your flag variables aren't static so the flags aren't shared between instances. In what looks like a second round of fix-ups, you start calling suppress and action directly. This violates the behavior paradigm that allows only Arbitrator to call these methods. Whether or not there is any practical problem with calling them, I don't really know.

What I've done is add the Cancel class. This cleanly allows suppress to do the correct thing. Note that action and suppress in Cancel do nothing; that's OK because the only desired effect of Cancel running is suppressing HitWall. I also moved the movement methods into their own class and made them static. This allows them to be used anywhere and makes the code cleaner. Both Cancel and HitWall listen to the touch sensor. I'm assuming that the listener thread is atomic for notifying the listening classes (hopefully that's a good assumption). I've also explicitly initialized the sensor to be a touch sensor; it doesn't seem to make a difference but it's good practice. Note that in the suppress methods, the motors are explicitly stopped. This probably isn't necessary since the suppressing behavior is quite likely to immediately turn the motors on and this stop may cause the robot to stutter unnecessarily.

I've tried running this and it seems to do the right thing. So, again good luck.

wjr

Gary Stoneman wrote:
Wow thanks for the insight. Its all very interesting to see how this all works. I currently have a solutions that seems to work adequately (there may well be some small lapses where things don't happen as they should, but it seems to function correctly). The solution was to add flags as you say, but just use them internally in the hitWall class. Using a thread for the hitWall we simply introduce a alreadyExecuted flag (called hit in the code) this is true if we are already executing the routine, if this is the case then we simply suppress the current behaviour and reset the flag. This of course means that the line of execution returns to the goForward class, which will most likely force the robot to strike an obstacle again and trigger another hitWall routine.

The only thing to improve on now would be instead of returning to the goForward after we suppress a hitWall (where suppress is triggered by another touch) we should instead rerun the hitWall immediately. Whilst I endeavour to correct this the current solution will work for likely 99% of the scenarios the robot will encounter.

I'll post the code again in case you want to have a look at it, its pretty straight forward (and quite messy as I have left lots of commented out code in). I'll have a look at your suggestions and see if I can come out with a working program.

Thanks
Gary

package MyRobot;

import josx.platform.rcx.*;
import josx.robotics.*;

public class GSBot {
    
    
    public static void main(String[] args) {
                Sensor.S1.setTypeAndMode (1, 0x20); // set to touch sensor
                Sensor.S1.activate();
        Behavior hit = new HitWall();
        Behavior can = new Cancel();
        Behavior move = new GoForward();
        Behavior[] behaviorArray = {move, hit, can};
        Arbitrator arbitrator = new Arbitrator(behaviorArray);
        arbitrator.start();
    }
}

class Cancel implements Behavior, SensorListener {
        
        boolean hitFlg = false;
        Cancel() {
                Sensor.S1.addSensorListener(this);
        }
        
        public boolean takeControl() {
                if (hitFlg) {
                        hitFlg = false;
                        return true;
                }
                return false;
        }
        
        public void action() {
        }
        
        public void suppress() {
        }
                
    public void stateChanged(Sensor bumper, int oldValue, int newValue) {
        if (newValue == 1) hitFlg = true;
    }
}

class HitWall implements Behavior, SensorListener {

    Thread runaThread;
    boolean hitFlg = false;
        
    HitWall() {
        Sensor.S1.addSensorListener(this);
    }
    
    public boolean takeControl() {
        return hitFlg;
    }
    
    public void suppress() {
        runaThread.interrupt();
                Move.stop();
    }
    
    public void action() {
        runaThread = Thread.currentThread();
        try {
            hitFlg = false;
            //Here is were we respond to the sensor
            Move.turnRight();
            Thread.sleep(1183);
            Move.moveForward();
            Thread.sleep(1800);
            Move.turnRight();
            Thread.sleep(1183);
        } catch (Exception e) {
            
        }
    }
        //runaThread = null;

    public void stateChanged(Sensor bumper, int oldValue, int newValue) {
        if (newValue == 1) hitFlg = true;
    }
}

class GoForward implements Behavior {
    Thread runThread;
    
    public boolean takeControl() {
        return true;
    }
    
    public void suppress() {
        runThread.interrupt();
        Motor.A.stop();
        Motor.C.stop();
    }
    
    public void action() {
        runThread = Thread.currentThread();
        try {
            Move.moveForward();
            Thread.sleep(1800);
            Move.moveForward();
            Thread.sleep(1800);
            Move.moveBackward();
            Thread.sleep(1800);
        } catch(Exception w) {
            //Down to here, then we respond
        }
        
    }
}

class Move {

    public static void moveForward() {
            Motor.A.forward();
        Motor.C.forward();
    }
    
    public static void moveBackward() {
        Motor.A.backward();
        Motor.C.backward();
    }
            
    public static void turnRight() {
        Motor.A.forward();
        Motor.C.backward();
    }
            
    public static void turnLeft() {
        Motor.A.backward();
        Motor.C.forward();
    }

    public static void stop() {
        Motor.A.stop();
        Motor.C.stop();
        }
}

Reply via email to