... | ... | @@ -156,11 +156,204 @@ public void action() { |
|
|
Thread.yield(); //don't exit till suppressed
|
|
|
}
|
|
|
```
|
|
|
>
|
|
|
|
|
|
##### Fig. 8: The action method of the lookForTarget behavior.
|
|
|
>
|
|
|
|
|
|
[![image alt text](http://img.youtube.com/vi/RjFRPIYJg_g/0.jpg)](http://www.youtube.com/watch?v=RjFRPIYJg_g)
|
|
|
##### Fig. 9: A video of the lookForTarget behavior. The robot is started on the wrestling arena and turns in place. A small glich occurs, probably due to a wrong reading of the ultrasonic sensors.
|
|
|
>
|
|
|
|
|
|
#### Behavior 2
|
|
|
|
|
|
The charge behavior uses two ultrasonic sensors to measure the distance in front of the robot. If a target comes into view, the robot will drive straight into the target, with the motors set to the a higher speed to quickly ram the opponent.
|
|
|
|
|
|
The distances that the object has to be in front of the robot is determined in the if statement; if (leftDistance < 60 || rightDistance < 60 ). Here it is important the the distances is set far enough that the sensors can measure across the hole wrestling arena. If it is set too low, the robot will start its lookForTarget behavior and essentially become a sitting target for the opponent. The ful class code can be seen in fig. 10
|
|
|
|
|
|
```
|
|
|
class Charge extends Thread implements Behavior
|
|
|
{
|
|
|
private boolean _suppressed = false;
|
|
|
private boolean active = false;
|
|
|
private int leftDistance = 255;
|
|
|
private int rightDistance = 255;
|
|
|
|
|
|
private UltrasonicSensor leftSonar;
|
|
|
private UltrasonicSensor rightSonar;
|
|
|
|
|
|
public Charge()
|
|
|
{
|
|
|
leftSonar = new UltrasonicSensor(SensorPort.S1);
|
|
|
rightSonar = new UltrasonicSensor(SensorPort.S4);
|
|
|
|
|
|
this.setDaemon(true);
|
|
|
this.start();
|
|
|
|
|
|
}
|
|
|
|
|
|
public void run()
|
|
|
{
|
|
|
Thread t1 = new Thread(new Runnable(){
|
|
|
|
|
|
@Override
|
|
|
public void run() {
|
|
|
while ( true ){
|
|
|
leftDistance = leftSonar.getDistance();
|
|
|
rightDistance = rightSonar.getDistance();
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
t1.start();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public int takeControl() {
|
|
|
// TODO Auto-generated method stub
|
|
|
if (leftDistance < 60 || rightDistance < 60 ) {
|
|
|
return 100;
|
|
|
}
|
|
|
else {
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void action() {
|
|
|
// TODO Auto-generated method stub
|
|
|
_suppressed = false;
|
|
|
|
|
|
//Do charge behavior
|
|
|
|
|
|
Motor.A.setSpeed(400*2);
|
|
|
Motor.C.setSpeed(400*2);
|
|
|
|
|
|
Motor.A.forward();
|
|
|
Motor.C.forward();
|
|
|
|
|
|
LCD.drawString("Charge ",0,2);
|
|
|
LCD.drawString("Distance: " + leftDistance, 0, 3);
|
|
|
|
|
|
int now = (int)System.currentTimeMillis();
|
|
|
while (!_suppressed && ((int)System.currentTimeMillis()< now + 200) )
|
|
|
{
|
|
|
|
|
|
Thread.yield(); //don't exit till suppressed
|
|
|
}
|
|
|
// Motor.A.stop(); // not strictly necessary, but good programming practice
|
|
|
// Motor.C.stop();
|
|
|
LCD.drawString("Charge stopped ",0,2);
|
|
|
|
|
|
//End with active = false;
|
|
|
Motor.A.setSpeed(400);
|
|
|
Motor.C.setSpeed(400);
|
|
|
active = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void suppress() {
|
|
|
// TODO Auto-generated method stub
|
|
|
_suppressed = true;// standard practice for suppress methods
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
##### Fig. 10. The charge class. The takeControl method determines at what distance to the object the robot should charge and the action method determines what the robot will do while the behavior is active.
|
|
|
>
|
|
|
|
|
|
We found that it was important to lower the motor speed at the end of the behavior, as an increased speed would cause the robot to drive over the edge of the arena before it has time to stop.
|
|
|
|
|
|
Our first build as seen in fig. 1 had the ultrasonic sensors mounted on the side of the robot. We found that there was a blind spot in the middle between the two sensors, which caused the robot to resume the lookForTarget behavior. To fix this, we mounted the sensors closer together (see fig 11) which enabled the robot to see the target even if it was right up against the pushing surface. A video of the behavior in action can be seen in fig. 12.
|
|
|
|
|
|
![sensor close](http://gitlab.au.dk/uploads/group-22/lego/ba5cea305b/sensor_close.jpg)
|
|
|
##### Fig. 11: The second build with ultrasonic sensors mounted closer together to avoid a blind spot.
|
|
|
>
|
|
|
|
|
|
[![image alt text](http://img.youtube.com/vi/SSMt-9nNxjo/0.jpg)](http://www.youtube.com/watch?v=SSMt-9nNxjo)
|
|
|
##### Fig. 12. The robot turns as of the first behavior. The charge behavior is first triggered by a man walking by, but then it finds the target and pushes it over the edge.
|
|
|
>
|
|
|
|
|
|
#### Behavior 3
|
|
|
|
|
|
The behaviour located in the Survive class has the highest priority as mentioned earlier.
|
|
|
A thread constantly takes readings from the light sensor and if it reads something with a higher (lighter) value than 48 (the color black with margin for error), it should back up by rotating 720 degrees (two rotations) backwards on both motors (see fig. 13). A video of the behavior in action can be seen in fig/video ???.(Indsæt link til video)
|
|
|
|
|
|
```
|
|
|
public void run()
|
|
|
{
|
|
|
Thread t1 = new Thread(new Runnable(){
|
|
|
|
|
|
@Override
|
|
|
public void run() {
|
|
|
while ( true ) lightValue = light.readValue();
|
|
|
}
|
|
|
});
|
|
|
t1.start();
|
|
|
}
|
|
|
|
|
|
public int takeControl() {
|
|
|
// TODO Auto-generated method stub
|
|
|
|
|
|
if(lightValue > 48) {
|
|
|
return 200;
|
|
|
}
|
|
|
else {
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public void action() {
|
|
|
// TODO Auto-generated method stub
|
|
|
_suppressed = false;
|
|
|
LCD.drawString("Survive: ",0,2);
|
|
|
LCD.drawInt(lightValue,0,3);
|
|
|
LCD.refresh();
|
|
|
|
|
|
int now = (int)System.currentTimeMillis();
|
|
|
while (!_suppressed && ((int)System.currentTimeMillis()< now + 1000))
|
|
|
{
|
|
|
|
|
|
Motor.A.rotate(-720, true);// start Motor.A rotating backward
|
|
|
Motor.C.rotate(-720, true); // start Motor.C rotating backward
|
|
|
|
|
|
Thread.yield(); //don't exit till suppressed
|
|
|
}
|
|
|
```
|
|
|
##### Fig. 13: The survive class. The light values are updated in a thread to make sure the robot always sees the white border of the wrestling arena.
|
|
|
>
|
|
|
|
|
|
[![image alt text](http://img.youtube.com/vi/ooSZfTtwdL0/0.jpg)](http://www.youtube.com/watch?v=ooSZfTtwdL0)
|
|
|
##### Fig. 14: The robot is triggered by a person to drive towards the edge. When it crosses the white border, the survive behavior takes over and the robot backs up.
|
|
|
>
|
|
|
|
|
|
#### Behavior 4
|
|
|
|
|
|
As a convenience we added an exit behavior to the robot as seen in fig. 15. This was just in case we needed to stop the program at any time during a match.
|
|
|
>
|
|
|
|
|
|
|
|
|
```
|
|
|
class Exit implements Behavior
|
|
|
{
|
|
|
private boolean _suppressed = false;
|
|
|
|
|
|
public int takeControl()
|
|
|
{
|
|
|
if ( Button.ESCAPE.isPressed()) {
|
|
|
return 300; } else {
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public void suppress()
|
|
|
{
|
|
|
_suppressed = true;// standard practice for suppress methods
|
|
|
}
|
|
|
|
|
|
public void action()
|
|
|
{
|
|
|
System.exit(0);
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
##### Fig. 15: The exit behavior class. A simple way to stop the robot during a match. |