... | @@ -44,21 +44,32 @@ Two light sensors are placed in the front of the LEGO car point downwards. Again |
... | @@ -44,21 +44,32 @@ Two light sensors are placed in the front of the LEGO car point downwards. Again |
|
|
|
|
|
The line following capabilities is somewhat improved by adding an extra sensor. The LEGO car now follows the center of the black line instead of an edge. However, the PID regulation is slow. When the LEGO car approaches the black line from an angle the PID regulation is not able to correct for this angle and steer the LEGO car onto the black line. In this case the LEGO car just crosses the line. By inspection the cause of this problem is narrowed down to the motor control which seems relatively slow thereby affecting the PID regulation.
|
|
The line following capabilities is somewhat improved by adding an extra sensor. The LEGO car now follows the center of the black line instead of an edge. However, the PID regulation is slow. When the LEGO car approaches the black line from an angle the PID regulation is not able to correct for this angle and steer the LEGO car onto the black line. In this case the LEGO car just crosses the line. By inspection the cause of this problem is narrowed down to the motor control which seems relatively slow thereby affecting the PID regulation.
|
|
|
|
|
|
In the beginning of the lesson it was estimated that the LeJOS differential pilot would be the optimal solution for motor control due to its use of the tachometer. Since the turning methods of this class takes a value in degrees and a radius as input it seemed as the obvious choice in order to simply the programming of the turns. When using this class, a speed and an acceleration is defined and in order to steer the `steer()` method is called. This method takes an input from -200 to 200 as input and steers the LEGO car accordingly. The problem is that even at an extreme turn rate (200 or -200) the one motor only slows down and never turns in the opposite direction. Therefore sharp turns are excluded when using the differential pilot.
|
|
In the beginning of the lesson it was estimated that the LeJOS `DifferentialPilot` would be the optimal solution for motor control due to its use of the tachometer. Since the turning methods of this class takes a value in degrees and a radius as input it seemed as the obvious choice in order to simply the programming of the turns. When using this class, a speed and an acceleration is defined and in order to steer the `steer()` method is called. This method takes an input from -200 to 200 as input and steers the LEGO car accordingly. The problem is that even at an extreme turn rate (200 or -200) the reaction of the 'DifferentialPilot' is too slow, and not extreme enough to keep the robot on track. Therefore sharp turns are excluded when using the differential pilot.
|
|
|
|
|
|
The solution is to change from the differential pilot to direct motor control using the leJOS MotorPort class. This greatly improves the PID regulation of the LEGO car.
|
|
The solution is to change from the `DifferentialPilot` to direct motor control using the leJOS `MotorPort` class. This greatly improves the PID regulation of the LEGO car.
|
|
|
|
|
|
|
|
|
|
## Adding behavioral control
|
|
## Adding behavioral control
|
|
|
|
|
|
### Setup
|
|
### Setup
|
|
|
|
|
|
With the plateau detection and line following functionality in place it is time combine these elements into a single program. For this we will use the behavior control paradigm from lesson 7 [4].
|
|
With the plateau detection and line following functionality in place it is time combine these elements into a single program. For this we will use the behavior control paradigm from lesson 7 [4]. The implementation we used in our project follows a slightly different approach. Instead of each behavior containing a `SharedCar` object, each behavior now implements the interface `Behavior`:
|
|
|
|
|
|
|
|
```java
|
|
|
|
public interface Behavior {
|
|
|
|
public abstract void Start(); //start the thread associated with this behavior
|
|
|
|
public abstract boolean HasAction();
|
|
|
|
public abstract void PerformAction(Car car);
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
The `Arbiter` class then passes a `Car` object to each behavior when they are selected to perform an action. The `Car` object provides various methods to control the robot, which is described further below.
|
|
|
|
|
|
The two behaviors are implemented as shown in the following diagram.
|
|
The two behaviors are implemented as shown in the following diagram.
|
|
|
|
|
|
![Behavioral control](https://gitlab.au.dk/rene2014/lego/raw/master/Lesson8/Images/BehavioralControl.jpg)
|
|
![Behavioral control](https://gitlab.au.dk/rene2014/lego/raw/master/Lesson8/Images/BehavioralControl.jpg)
|
|
|
|
|
|
The Arbiter contains a list of the behaviors and constantly check, in a prioritized manor, if the behavior has available commands. This will ensure that the behavior with the highest priority will control the LEGO car, if it has any commands for it.
|
|
The `Arbiter` contains a list of the behaviors and constantly check, in a prioritized manner, if the behavior has available commands. This will ensure that the behavior with the highest priority will control the LEGO car, if it has any commands for it.
|
|
|
|
|
|
An overview of the track and where each behavior is activated is shown in the following figure.
|
|
An overview of the track and where each behavior is activated is shown in the following figure.
|
|
|
|
|
... | @@ -72,10 +83,6 @@ The implementation of this is shown in the following code snippet. |
... | @@ -72,10 +83,6 @@ The implementation of this is shown in the following code snippet. |
|
|
|
|
|
```java
|
|
```java
|
|
switch (nextAction) {
|
|
switch (nextAction) {
|
|
case pass: //starting at the bottom.
|
|
|
|
nextAction = ActionType.rightTurn;
|
|
|
|
...
|
|
|
|
break;
|
|
|
|
case rightTurn:
|
|
case rightTurn:
|
|
car.TurnRight();
|
|
car.TurnRight();
|
|
nextAction = ActionType.leftTurn; //every right turn is preceded by a left turn
|
|
nextAction = ActionType.leftTurn; //every right turn is preceded by a left turn
|
... | @@ -105,9 +112,35 @@ switch (nextAction) { |
... | @@ -105,9 +112,35 @@ switch (nextAction) { |
|
break;
|
|
break;
|
|
}
|
|
}
|
|
```
|
|
```
|
|
The FSM is responsible for performing all turns on the track. By letting the FSM control the stopping mechanism we avoid having a third behavior that uses the light sensor or an additional color sensor to detect when the LEGO car is in the green end zone.
|
|
The FSM is responsible for performing all turns on the track using an instance of the `Car` class provided by the Arbiter. The methods of the `Car` class is described below. By letting the FSM control the stopping mechanism we avoid having a third behavior that uses the light sensor or an additional color sensor to detect when the LEGO car is in the green end zone.
|
|
|
|
|
|
Each turn is hard coded by imposing a certain power to each motor in a fixed amount of time. The amount of power and the time interval is then adjusted according to manual inspection.
|
|
The 180 degree rotation is implemented using the `rotate(degree)` method of the `NXTRegulatedMotor` as follows:
|
|
|
|
|
|
|
|
```java
|
|
|
|
public void Rotate180()
|
|
|
|
{
|
|
|
|
leftMotor.setSpeed((int)(getMaxSpeed()*0.7));
|
|
|
|
rightMotor.setSpeed((int)(getMaxSpeed()*0.7));
|
|
|
|
leftMotor.rotate(370,true);
|
|
|
|
rightMotor.rotate(-370,true);
|
|
|
|
leftMotor.waitComplete();
|
|
|
|
rightMotor.waitComplete();
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Each turn is hard coded by imposing a certain power to each motor in a fixed amount of time. The amount of power and the time interval is then adjusted according to manual inspection. Turning is different whether the robot is ascending or descending, and left and right turns are not implemented precisely symmetrical, because the left and right motors run slightly different. All turns follow the same pattern and is implemented as follows:
|
|
|
|
|
|
|
|
```java
|
|
|
|
public void TurnRightUp()
|
|
|
|
{
|
|
|
|
final int innerPower = 37;
|
|
|
|
final int outerPower = 100;
|
|
|
|
|
|
|
|
Forward(innerPower, outerPower);
|
|
|
|
|
|
|
|
Delay.msDelay(1350);
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
The hardware setup is identical to previously.
|
|
The hardware setup is identical to previously.
|
|
|
|
|
... | | ... | |