... | @@ -6,7 +6,7 @@ |
... | @@ -6,7 +6,7 @@ |
|
|
|
|
|
**Group members participating:** Camilla M. V. Frederiksen, Ida Larsen-Ledet, Nicolai Nibe and Emil Platz
|
|
**Group members participating:** Camilla M. V. Frederiksen, Ida Larsen-Ledet, Nicolai Nibe and Emil Platz
|
|
|
|
|
|
**Activity duration:** 29 hours
|
|
**Activity duration:** 30 hours
|
|
|
|
|
|
8 hours on Thursday 28th (All)
|
|
8 hours on Thursday 28th (All)
|
|
|
|
|
... | @@ -16,7 +16,7 @@ |
... | @@ -16,7 +16,7 @@ |
|
|
|
|
|
9 hours on Thursday the 5th (Emil, Ida, Nicolai)
|
|
9 hours on Thursday the 5th (Emil, Ida, Nicolai)
|
|
|
|
|
|
8 hours on Monday the 9th (Camilla, Emil, Ida og Nicolai)
|
|
9 hours on Monday the 9th (Camilla, Emil, Ida og Nicolai)
|
|
|
|
|
|
## **Goal**
|
|
## **Goal**
|
|
|
|
|
... | @@ -70,7 +70,7 @@ We decided to begin by testing the use of different sensors, with regards to fol |
... | @@ -70,7 +70,7 @@ We decided to begin by testing the use of different sensors, with regards to fol |
|
|
|
|
|
We ended up with the following initial, concrete plan for the first steps:
|
|
We ended up with the following initial, concrete plan for the first steps:
|
|
|
|
|
|
1. Run the LineFollower program from Lesson 1 on the track to see how it performs
|
|
1. Run the LineFollower [TODO ref] program from Lesson 1 on the track to see how it performs
|
|
|
|
|
|
2. Experiment with modifications of LineFollower
|
|
2. Experiment with modifications of LineFollower
|
|
|
|
|
... | @@ -114,17 +114,21 @@ In order to have some clear goals for our experiments, we began by identifying i |
... | @@ -114,17 +114,21 @@ In order to have some clear goals for our experiments, we began by identifying i |
|
|
|
|
|
*Table 1: Issues with the LineFollower program.*
|
|
*Table 1: Issues with the LineFollower program.*
|
|
|
|
|
|
TODO: Manuel konvertering af tabellen ovenfor
|
|
TODO: Manuel konvertering af tabellen
|
|
|
|
|
|
We became aware that some of the identified issues express behaviors, while others express triggers.
|
|
We became aware that some of the identified issues express behaviors, while others express triggers.
|
|
|
|
|
|
#### Running and modifying
|
|
#### Running and modifying
|
|
|
|
|
|
We performed an initial run with the LineFollower program as it was in Lesson 1. Following the line went fine when going up the first ramp, but then the robot lost track of the line and nearly toppled over the edge. Going down, the robot followed the line for a while, before turning (and driving TODOQ?? Emil) into a wall. Later on in our experiments, we realized that the inexplicable turns were caused by the robot’s rear support wheel.
|
|
We performed an initial run with the LineFollower program as it was in Lesson 1. Following the line went fine when going up the first ramp, but then the robot lost track of the line and nearly toppled over the edge. Going down, the robot followed the line for a while, before turning into a wall. Later on in our experiments, we realized that the inexplicable turns were caused by the robot’s rear support wheel.
|
|
|
|
|
|
TODO: video med første run af LineFollower på rampen?
|
|
TODO: Fix to markdown format
|
|
|
|
|
|
The LineFollower program from Lesson 1, when attempting to correct the robot’s course, turns the robot by only having one motor turned on. This was observable when we ran the program [TODOQ: hvordan?]. We had already, in the very beginning of our experiments, discussed modifying the program so that the robot would always use both motors. The purpose of this modification would be to increase the forward motion along the desired path such that less time would be wasted in the turns.
|
|
https://www.youtube.com/watch?v=BOtnwWpyBlk
|
|
|
|
|
|
|
|
*Video 1: First run of LineFollower*
|
|
|
|
|
|
|
|
The LineFollower program from Lesson 1, when attempting to correct the robot’s course, turns the robot by only having one motor turned on, which we also observed when we ran the program. We had already, in the very beginning of our experiments, discussed modifying the program so that the robot would always use both motors. The purpose of this modification would be to increase the forward motion along the desired path such that less time would be wasted in the turns.
|
|
|
|
|
|
We decided to give it a try - a description of the outcome follows.
|
|
We decided to give it a try - a description of the outcome follows.
|
|
|
|
|
... | @@ -134,7 +138,7 @@ The robot was still moving very slowly, so we changed the motor powers in the tu |
... | @@ -134,7 +138,7 @@ The robot was still moving very slowly, so we changed the motor powers in the tu |
|
|
|
|
|
#### Experimenting with faster initial ramp climb
|
|
#### Experimenting with faster initial ramp climb
|
|
|
|
|
|
We wanted to find a faster method for climbing the first ramp than using the old LineFollower program. As described, we initially disabled line following and instead used the program FullDowney.java which simply makes the robot drive forward with full speed. We did this to see if, by positioning it correctly, we could get the robot to go straight up and not drive off the ramp.
|
|
We wanted to find a faster method for climbing the first ramp than using the old LineFollower program. As described, we initially disabled line following and instead used the program **FullDowney.java **[TODO ref] which simply makes the robot drive forward with full speed. We did this to see if, by positioning it correctly, we could get the robot to go straight up and not drive off the ramp.
|
|
|
|
|
|
The robot performed very poorly, often making a sudden turn off the track. After taking a closer look, we ended up replacing the left motor, a lego-stick-thing [TODO Ida: "change slightly bent sticky-thing to not bent sticky-thing" - tror at “sticky” = pinde-agtig, ikke klistret], and the support wheel. This seemed to improve the robot’s driving slightly, but did not fix the issues with seemingly random turns completely. We gave up on trying to get the robot to go straight without sensor input and went on to experimenting with the gyro sensor.
|
|
The robot performed very poorly, often making a sudden turn off the track. After taking a closer look, we ended up replacing the left motor, a lego-stick-thing [TODO Ida: "change slightly bent sticky-thing to not bent sticky-thing" - tror at “sticky” = pinde-agtig, ikke klistret], and the support wheel. This seemed to improve the robot’s driving slightly, but did not fix the issues with seemingly random turns completely. We gave up on trying to get the robot to go straight without sensor input and went on to experimenting with the gyro sensor.
|
|
|
|
|
... | @@ -142,33 +146,15 @@ The robot performed very poorly, often making a sudden turn off the track. After |
... | @@ -142,33 +146,15 @@ The robot performed very poorly, often making a sudden turn off the track. After |
|
|
|
|
|
The next experiment was whether or not equipping the robot with a gyro sensor would enable it to detect the movement when driving onto a platform.
|
|
The next experiment was whether or not equipping the robot with a gyro sensor would enable it to detect the movement when driving onto a platform.
|
|
|
|
|
|
As in the other experiments we started out by rebuilding the robot - this time using the gyro sensor. Initially we intended to place the sensor at the center of the robot (directly above the wheels). We however realized that there would be less motion on the center axis than on either front or back of the robot, resulting in more steady readings of the gyro, which in our case, where we want to detect small changes, is an unwanted property. Therefore we decided to mount the gyro in front of the robot as seen in figure 4.
|
|
As in the other experiments we started out by rebuilding the robot - this time using the gyro sensor. Initially we intended to place the sensor at the center of the robot (directly above the wheels). We however realized that there would be less motion on the center axis than on either front or back of the robot, resulting in more steady readings of the gyro, which in our case, where we want to detect small changes, is an unwanted property. Therefore we decided to mount the gyro in front of the robot as seen in figure 3.
|
|
|
|
|
|
[TODO robot with gyro sensor]
|
|
[TODO robot with gyro sensor]
|
|
|
|
|
|
*Figure 3: The robot rebuilt to use a gyro sensor for detecting a level change.*
|
|
*Figure 3: The robot rebuilt to use a gyro sensor for detecting a level change.*
|
|
|
|
|
|
To test whether the gyro sensor can be used to detect when the robot reaches a platform, we wrote a small program GyroTest.java, that records and displays the minimum - and maximum seen values so far while the robot drives forward at a steady paste (both motors run with a power of 80). We intended to log the gyro readings throughout each test, but had some errors that we couldn’t find an immediate solution for. Instead we moved on without logs and used the displayed minimum - and maximum values instead.
|
|
To test whether the gyro sensor can be used to detect when the robot reaches a platform, we wrote a small program **GyroTest.java **[TODO ref], that records and displays the minimum - and maximum seen values so far while the robot drives forward at a steady paste (both motors run with a power of 80). We intended to log the gyro readings throughout each test, but had some errors that we couldn’t find an immediate solution for. Instead we moved on without logs and used the displayed minimum - and maximum values instead.
|
|
|
|
|
|
Running the GyroTest.java program was done in two tries. First we started the program on the ramp just before the platform, letting the robot drive onto the platform and reading the maximal and minimal seen gyro values. Secondly we decided to let the robot gain some momentum before driving onto the platform, and therefore started it at the bottom of the ramp and let it drive all the way up onto the platform. Neither of these runs gave a noticeable result that we felt we could rely on, when attempting to detect that the robot reached a platform and therefore should start behaving differently. We ended up discarding the idea of using a gyro sensor as a way of detecting the platform and moved on to build a robot that with no idea of time-consumption climbed the ramp and returned to the floor.
|
|
|
|
|
|
|
|
[TODOQ: har vi max og min værdier til ovenstående? Ellers mener jeg at det var maksimal max 610 og minimalt min 580 /Camilla]
|
|
|
|
|
|
|
|
#### Line following with two light sensors
|
|
|
|
|
|
|
|
As the robot was going way too slow with the initial values, we decided to increase the motor power of the non-turning motor in the Line2Sensor program to 50 instead of 0. This made the robot turn of the ramp as seen in video Z [TODO].
|
|
|
|
|
|
|
|
[TOOD: Indsæt video hvor robot kører ned af første rampe og kører af - Ida siger ‘Uhh’]
|
|
|
|
|
|
|
|
Video … :
|
|
|
|
|
|
|
|
This reaction is probably caused by the robot not responding rapidly enough to losing the line, as we actually see the robot trying to correct its path a bit when driving of the line, but ending up driving off the ramp either way. This reaction however gave us the idea of introducing a PID controller to our program, such that the the robot would turn more rapidly towards the last direction it saw the line when going away from its correct path. … [TODOQ: Ved ikke hvordan jeg skal flette den følgende note ind /Camilla] …
|
|
|
|
|
|
|
|
NOTER:
|
|
|
|
|
|
|
|
Forslag: PID-inspired integral control - så de seneste målinger tages into account (også en optimering)
|
|
Running the GyroTest.java program was done in two tries. First we started the program on the ramp just before the platform, letting the robot drive onto the platform and reading the maximal and minimal seen gyro values. Secondly we decided to let the robot gain some momentum before driving onto the platform, and therefore started it at the bottom of the ramp and let it drive all the way up onto the platform. Neither of these runs gave a noticeable result that we felt we could rely on, when attempting to detect that the robot reached a platform and therefore should start behaving differently. This might have been a result of us driving with a fairly slow speed initially, where a faster robot would have had an easier time triggering significant gyro sensor readings. From our experiences in previous lessons, we did not feel like running the risk of spending several hours on attempting an approach that did not seem to promise a useful result. Therefore, we ended up discarding the idea of using a gyro sensor as a way of detecting the platform and moved on to build a robot that with no concern of time-consumption climbed the ramp and returned to the floor.
|
|
|
|
|
|
We however decided that the initial goal was to build a robot that was able to climb the ramp but with no concern of speed. Therefore we noted the above optimization suggestions and moved on to experiment with using the gyro sensor to detect entry onto a platform.
|
|
|
|
|
|
|
|
### Making a basic up-down robot
|
|
### Making a basic up-down robot
|
|
|
|
|
... | @@ -180,7 +166,7 @@ We started out by rebuilding the robot such that it now had two light sensors in |
... | @@ -180,7 +166,7 @@ We started out by rebuilding the robot such that it now had two light sensors in |
|
|
|
|
|
*Figure 4: The robot rebuilt to use two light sensor for following a line on the ground.*
|
|
*Figure 4: The robot rebuilt to use two light sensor for following a line on the ground.*
|
|
|
|
|
|
After rebuilding the robot, we began implementing the **InitialClimber.java** program. The program started out as a copy of **LineFollower.java**, and the idea was to use one of the two sensors to follow the line on the ramp, and the other to detect and initiate a turn at the big black line at the end of the platforms. The general idea can be seen in figure 5.
|
|
After rebuilding the robot, we began implementing the **_InitialClimber.java_** [TODO ref] program. The program started out as a copy of **_LineFollower.java_**** **[TODO ref], and the idea was to use one of the two sensors to follow the line on the ramp, and the other to detect and initiate a turn at the big black line at the end of the platforms. The general idea can be seen in figure 5.
|
|
|
|
|
|
[TODO: Lav illustration af ideen]
|
|
[TODO: Lav illustration af ideen]
|
|
|
|
|
... | @@ -188,55 +174,51 @@ After rebuilding the robot, we began implementing the **InitialClimber.java** pr |
... | @@ -188,55 +174,51 @@ After rebuilding the robot, we began implementing the **InitialClimber.java** pr |
|
|
|
|
|
The extension of the code consisted in an if-statement checking if both sensors were reading black. If this was the case, the robot should turn a little less than 180 degrees and thereby drive towards the next ramp where the hope was that it would be able to rediscover the black line. We purposefully set the power for the motors very low, in order to more easily observe errors. The turn was implemented by rotating the robot while letting the thread sleep for a certain amount of milliseconds - the sleep time was figured out by performing test runs with the robot to try out different values.
|
|
The extension of the code consisted in an if-statement checking if both sensors were reading black. If this was the case, the robot should turn a little less than 180 degrees and thereby drive towards the next ramp where the hope was that it would be able to rediscover the black line. We purposefully set the power for the motors very low, in order to more easily observe errors. The turn was implemented by rotating the robot while letting the thread sleep for a certain amount of milliseconds - the sleep time was figured out by performing test runs with the robot to try out different values.
|
|
|
|
|
|
Running this program resulted in the robot driving exceptionally slow up the ramp. As the robot drove onto the platform it kept on following the line, but instead of driving all the way to the end of the platform it started turning in the middle where the three black lines of the Y-shape meet. This can be seen in video .. [TODO number].
|
|
Running the InitialClimber program resulted in the robot driving exceptionally slow up the ramp. As the robot drove onto the platform it kept on following the line, but instead of driving all the way to the end of the platform it started turning in the middle where the three black lines of the Y-shape meet. This can be seen in Video 2.
|
|
|
|
|
|
[TODO: Indsæt video, hvor Ida siger ‘OHH Myyy Gooood!’ og roboten drejer for meget ved Y’et]
|
|
|
|
|
|
|
|
We reasoned that the premature turn in the middle of the platform was caused by the two sensors coincidentally being positioned above each their "arm" of the Y and thus both reading black at the same time, thereby triggering the turn. Instead of moving the sensors further away from each other, to try and stop them from seeing black in the middle of the platform, we decided to decrease the turn, as turning in the center instead of at the edge would decrease the total time spend on the track and thereby improve our solution. We decreased the turn time and tried again.
|
|
|
|
|
|
|
|
[TODO: indsæt video hvor den kravler til platform 2]
|
|
|
|
|
|
|
|
As seen in Video [TODO number] we succeeded in getting the robot to drive onto the next ramp by adjusting the turn time, but as the robot reached the second platform it read black on both sensors and began the turning behavior of the previous platform, it turned the wrong way and began driving down the ramp it had just climbed. This was as expected, as we had only implemented the turn for the first ramp. We then introduced a boolean variable, **turnRight**, initially set to true. The turn behavior (left or right) would then be selected according to this value, and would negate the value of the variable upon entry. Running this program, we observed the robot behave exactly as before the introduction of **turnRight** (see Video [TODO nummer]).
|
|
[TODO: Fix to markdown video format]
|
|
|
|
|
|
We discussed whether the angle was too pointy when the robot was climbing on the left side of the line on the second platform, but concluded that this still wouldn’t make it turn to the right, as it should turn left by our new boolean variable, **turnRight**. We concluded that something was wrong with how this variable was updated and decided to display it’s value in the robot’s screen. Running the program again, we now observed that **turnRight** was *true* as the robot went up the second ramp. We were never sure why this was happening, but speculated that it might be because the sensors were both reading black at some point during the right turn on the first platform, which would flip the variable one time too many and result in the robot making a right turn on the second platform when it should in fact turn left. Another explanation might be that the robot performed the first observed turn simply as part of its correction in order to follow the line and not because both sensors read black, in which case **turnRight** would not be flipped on the first platform.
|
|
https://www.youtube.com/watch?v=On_NV-g9-js
|
|
|
|
|
|
After closely observing several different runs of the same program, we concluded that the robot was not behaving the exact same way each time, as its entrance onto the platform was different for every run. We therefore decided to improve the line following behavior to make the robot follow the line more closely - this way, the platform entrances should be more similar as the robot’s entrance angle would not diverge as much. We figured that the best way to obtain more smooth line following behavior would be to use PID control.
|
|
*Video 2: Initial run of InitialClimber, where the robot surpricingly turns in the middle of the first platform.*
|
|
|
|
|
|
#### Introducing PID control
|
|
We reasoned that the premature turn in the middle of the platform was caused by the two sensors coincidentally being positioned above each their "arm" of the Y and thus both reading black at the same time, thereby triggering the turn. Instead of moving the sensors further away from each other, to try and stop them from seeing black in the middle of the platform, we decided to decrease the turn, as turning in the center instead of at the edge would decrease the total time spend on the track and thereby improve our solution. We decreased the turn time and tried again.
|
|
|
|
|
|
We made the class **_PIDClimber.java_** which uses the same kind of correction as **_PIDpolice.java_** in Lesson 4, simply multiplying the deviation from the setpoint by a constant. In **_PIDClimber_**, the robot interprets black as a sensor measuring less than the black/white threshold (used as the setpoint). This resulted in the robot triggering a turn when its front was being pushed over the edge of the platform, as the sensors were raised too far from the platform to register the white surface. Instead, we tried comparing with the light reading for black (plus a small margin), which successfully got rid of the undesired triggering of turns. The robot still missed a few turns once in a while, most likely due to the same issue that was described in the previous section with the line following behavior performing the turn on its own and missing the double black reading. To remedy this, we tried lowering the speed of the robot. This reduced the number of occurrences of this kind of error.
|
|
[TODO: Fix to markdown video format]
|
|
|
|
|
|
The observations described above were not filmed, as we felt that our video documentation was turning into a giant blob of videos, and the improvements seemed minor.
|
|
https://www.youtube.com/watch?v=Use9_ANpYOA
|
|
|
|
|
|
##### Using two sensors to follow the line
|
|
*Video 3: Robot reaching second platform with the InitialClimber program*
|
|
|
|
|
|
-----
|
|
As seen in Video 3 we succeeded in getting the robot to drive onto the next ramp by adjusting the turn time, but as the robot reached the second platform it read black on both sensors and began the turning behavior of the previous platform, it turned the wrong way and began driving down the ramp it had just climbed. This was as expected, as we had only implemented the turn for the first ramp. We then introduced a boolean variable, **turnRight**, initially set to true. The turn behavior (left or right) would then be selected according to this value, and would negate the value of the variable upon entry. Running this program, we observed the robot behave exactly as before the introduction of **turnRight**.
|
|
|
|
|
|
PRØVER MED TO SENSORER, SOM ER PÅ HVER DERES SIDE AF STREGEN (caps igen)
|
|
We discussed whether the angle was too pointy when the robot was climbing on the left side of the line on the second platform, but concluded that this still wouldn’t make it turn to the right, as it should turn left by our new boolean variable, **turnRight**. We concluded that something was wrong with how this variable was updated and decided to display it’s value in the robot’s screen. Running the program again, we now observed that **turnRight** was *true* as the robot went up the second ramp. We were never sure why this was happening, but speculated that it might be because the sensors were both reading black at some point during the right turn on the first platform, which would flip the variable one time too many and result in the robot making a right turn on the second platform when it should in fact turn left. Another explanation might be that the robot performed the first observed turn simply as part of its correction in order to follow the line and not because both sensors read black, in which case **turnRight** would not be flipped on the first platform.
|
|
|
|
|
|
----------
|
|
After closely observing several different runs of the same program, we concluded that the robot was not behaving the exact same way each time, as its entrance onto the platform was different for every run. We therefore decided to improve the line following behavior to make the robot follow the line more closely - this way, the platform entrances should be more similar as the robot’s entrance angle would not diverge as much. We figured that the best way to obtain more smooth line following behavior would be to use PID control.
|
|
|
|
|
|
MODIFY InitialClimber.java:
|
|
#### Introducing PID control
|
|
|
|
|
|
* larger turn (by increasing time from 1000 ms to 2000 ms)
|
|
We made the class **_PIDClimber.java_** [TODO ref] which uses the same kind of correction as **_PIDpolice.java_** [TODO ref] in Lesson 4, simply multiplying the deviation from the setpoint by a constant. In **_PIDClimber_**, the robot interprets black as a sensor measuring less than the black/white threshold (used as the setpoint). This resulted in the robot triggering a turn when its front was being pushed over the edge of the platform, as the sensors were raised too far from the platform to register the white surface. Instead, we tried comparing with the light reading for black (plus a small margin), which successfully got rid of the undesired triggering of turns. The robot still missed a few turns once in a while, most likely due to the same issue that was described in the previous section with the line following behavior performing the turn on its own and missing the double black reading. To remedy this, we tried lowering the speed of the robot. This reduced the number of occurrences of this kind of error.
|
|
|
|
|
|
Should change to use tacho counter?
|
|
The observations described above were not filmed, as we felt that our video documentation was turning into a giant blob of videos, and the improvements seemed minor. Most of our work has not been video recorded, because almost all of our progress was an extremely incremental process where we ran a program dozens of times with minor changes between each run before we accomplished a small goal, and then moving on to tackling the next problem. It therefore became very difficult to judge when it made any sense to record videos at the time, and resulted in very few videos overall.
|
|
|
|
|
|
[TODOQ: beskriv at vi arbejdede med to forskellige forsøg på PID LineFollowing, hhv. Nicolais og Emils, og sørg for at beskrive forskellene mellem de to tilgange, når begge afsnit er skrevet - DENNE TODO SKAL NOK ORDNES AF NICOLAI OG EMIL!]
|
|
#### Using two sensors to follow the line
|
|
|
|
|
|
We divided the work amongst us so that we could try out a larger number of approaches concurrently. While discussing issues and how to handle them with each other, we each worked on separate implementations. We also regularly watched when another group member ran some code on the robot. As group members, we mainly served as rubber ducks for the other members’ verbalization of current problems being tackled, although we did also provide concrete input to each others’ solutions.
|
|
We figured that we could obtain greater precision by using both sensors to follow the line. We divided the work amongst us so that we could try out a larger number of approaches concurrently. While discussing issues and how to handle them with each other, we each worked on separate implementations. We also regularly watched when another group member ran some code on the robot. As group members, we mainly served as rubber ducks for the other members’ verbalization of current problems being tackled, although we did also provide concrete input to each others’ solutions.
|
|
|
|
|
|
As described previously, Nicolai and Emil worked on each their implementation of a PID-controlled line follower. Below, we present a description of both of these attempts as well as a discussion on the advantages and disadvantages of the two compared to each other [TODOQ: tror at sådan en sammenligning vil være en virkelig god idé /Ida].
|
|
As described previously, Nicolai and Emil worked on each their implementation of a PID-controlled line follower. One with a very high precisioning PID controller, another with use of tacho counter to perform turns. We decided to explore both solutions because one seemed to provide a more step-by-step reliable attempt at getting to the top and back down, whereas the other one had a much higher potential for a speedy run. Below, we present a description of both of these attempts.
|
|
|
|
|
|
### PID LineFollower with high precision
|
|
### PID LineFollower with high precision
|
|
|
|
|
|
In an attempt to improve our line follower we wanted to make several changes. First off, we started calibrating the two light sensors for seperate black/white light values using the BlackWhiteSensor.java program, in order to guard ourselves against potential small differences in values read by two difference sensors. Then a basic controller utilizing both light sensors properly was implemented by calculating the *error* value for both light sensors, *leftError* and *rightError* (Black-White threshold subtracted from light reading), multiplying left*Error* value by -1, and then adding it to *rightError* for a combined *turn* value. Inverting one sensors error was to ensure that the two sensors were working together to correct toward the center of the black line, as they would be placed so each sensor was attempting to stay on one of the black tapes borders (left sensor on the left border, and right sensor on the right border obviously). This combined *turn *value was then used by subtracting it from the robot’s left motor’s power, and adding it to the right motor’s power.
|
|
The goal of this implementation was to use PID control to very accurately follow the black line, in order to use the resulting reliable entrance angle of the Y-sections and black borders on the platforms to guide the robot. As such, **_GodBot.java_** [TODO ref] was made.
|
|
|
|
|
|
|
|
In an attempt to improve our line follower we wanted to make several changes. First off, we started calibrating the two light sensors for seperate black/white light values using the **_BlackWhiteSensor.java_** [TODO ref] program, in order to guard ourselves against potential small differences in values read by two difference sensors. Then a basic controller utilizing both light sensors properly was implemented by calculating the *error* value for both light sensors, *leftError* and *rightError* (Black-White threshold subtracted from light reading), multiplying left*Error* value by -1, and then adding it to *rightError* for a combined *turn* value. Inverting one sensors error was to ensure that the two sensors were working together to correct toward the center of the black line, as they would be placed so each sensor was attempting to stay on one of the black tapes borders (left sensor on the left border, and right sensor on the right border obviously). This combined *turn *value was then used by subtracting it from the robot’s left motor’s power, and adding it to the right motor’s power.
|
|
|
|
|
|
Running this program with a *targetPower* = 70 followed the line for the most part, but reacted far too violently to the line, causing big oscillations. It occurred to us that even though we didn’t implement P, I or D variables in the controller, the current program is basically a P controller with P = 2, since we are getting error values from two sensors and adding them together for doubled the effect on motor power. We solved this by simply dividing the *leftError + rightError* by 2 before adding to the motor’s power. This resulted in a robot that follows the line decently, although still oscillating a fair bit. We reduced the *targetPower* to 60, resulting in a *very* slow robot, but one that follows the line more steadily. As speed isn’t our top priority at the moment, we decided this was fine for an initial attempt at getting all the way to the top and back down.
|
|
Running this program with a *targetPower* = 70 followed the line for the most part, but reacted far too violently to the line, causing big oscillations. It occurred to us that even though we didn’t implement P, I or D variables in the controller, the current program is basically a P controller with P = 2, since we are getting error values from two sensors and adding them together for doubled the effect on motor power. We solved this by simply dividing the *leftError + rightError* by 2 before adding to the motor’s power. This resulted in a robot that follows the line decently, although still oscillating a fair bit. We reduced the *targetPower* to 60, resulting in a *very* slow robot, but one that follows the line more steadily. As speed isn’t our top priority at the moment, we decided this was fine for an initial attempt at getting all the way to the top and back down.
|
|
|
|
|
|
The robot now follows the line up until the end of the first ramp, but has trouble staying on the line during the sharp turn. Using the fact that we have 2 light sensors, we started storing a variable called *lastBlack*. This variable is a string set to "left" or “right” whenever left or right light sensor reads a black light value. Using this, whenever both light sensors read white (means we have driven off the black line), the robot will start steering right or left, according to which sensor most recently saw a black line, to get the robot back on track. This allowed the robot to very consistently make it past the first Y-section, to the back of the first platform.
|
|
The robot now follows the line up until the end of the first ramp, but has trouble staying on the line during the sharp turn. Using the fact that we have 2 light sensors, we started storing a variable called *lastBlack*. This variable is a string set to "left" or “right” whenever left or right light sensor reads a black light value. Using this, whenever both light sensors read white (means we have driven off the black line), the robot will start steering right or left, according to which sensor most recently saw a black line, to get the robot back on track. This allowed the robot to very consistently make it past the first Y-section, to the back of the first platform.
|
|
|
|
|
|
Next problem was turning around on the platform and following the line up the next ramp. Once the robot had seen black on both sensors a couple of program loops in a row (3-4), we made the robot turn right (Setting left and right motor powers to 70 and -70 respectively) for a certain defined amount of milliseconds, and then drive forward for another set amount of time, in an attempt to connect with the black line on the next ramp. In order to give ourselves some room for error in *shooting* for the next black line, we didn’t attempt to hit it dead on, instead we just wanted the robot to end up in roughly the right direction and to be on the left side of the black line. We could then just set our *lastBlack* variable to *right*, which would cause the robot to search on its right side for the black line, and once found, follow it up the next ramp. We could have used the Tacho counter for a more reliable turn, but in this iteration we felt the hardcoded time windows worked well enough.
|
|
Next problem was turning around on the platform and following the line up the next ramp. Once the robot had seen black on both sensors a couple of program loops in a row (3-4), we made the robot turn right (setting left and right motor powers to 70 and -70 respectively) for a certain defined amount of milliseconds, and then drive forward for another set amount of time, in an attempt to connect with the black line on the next ramp. In order to give ourselves some room for error in *shooting* for the next black line, we didn’t attempt to hit it dead on, instead we just wanted the robot to end up in roughly the right direction and to be on the left side of the black line. We could then just set our *lastBlack* variable to *right*, which would cause the robot to search on its right side for the black line, and once found, follow it up the next ramp. We could have used the Tacho counter for a more reliable turn, but in this iteration we felt the hardcoded time windows worked well enough.
|
|
|
|
|
|
We used the previously mentioned *turnRight* boolean to switch between the two turn behaviors when hitting the second platform. Additionally, after the robots second turn (the first left turn), we set a boolean *nextStopIsTop* to true. When the robot saw black on both sensors a few time in a row, it would first check if *nextStopIsTop* was true, and if so, it would drive forward a set amount of time, to get completely up on the top platform, then turn around 180, and drive forward a short time to get down on the ramp, before continuing its line following.
|
|
We used the previously mentioned *turnRight* boolean to switch between the two turn behaviors when hitting the second platform. Additionally, after the robots second turn (the first left turn), we set a boolean *nextStopIsTop* to true. When the robot saw black on both sensors a few time in a row, it would first check if *nextStopIsTop* was true, and if so, it would drive forward a set amount of time, to get completely up on the top platform, then turn around 180, and drive forward a short time to get down on the ramp, before continuing its line following.
|
|
|
|
|
... | @@ -244,15 +226,19 @@ The program as a whole worked some of the time, but it was especially difficult |
... | @@ -244,15 +226,19 @@ The program as a whole worked some of the time, but it was especially difficult |
|
|
|
|
|
##### Putting the P, I and D in PID.
|
|
##### Putting the P, I and D in PID.
|
|
|
|
|
|
One recurring problem when running our simple GodBot.java program, was that it didn’t follow the line very precisely, which caused inconsistencies in the angle at which the robot would enter the Y-section of the black tape trail, or the big black line at the end of the platforms. This inconsistency in entrance angle meant it was difficult to get the robot to properly get out of the Y-section, and follow the black line up the next ramp, as we couldn’t make any solid assumptions as to where exactly the robot would be when seeing the thick black ramp line, not to mention it didn’t always follow the line correctly past the Y-section to begin with.
|
|
One recurring problem when running our simple **_GodBot.java_** [TODO ref] program, was that it didn’t follow the line very precisely, which caused inconsistencies in the angle at which the robot would enter the Y-section of the black tape trail, or the big black line at the end of the platforms. This inconsistency in entrance angle meant it was difficult to get the robot to properly get out of the Y-section, and follow the black line up the next ramp, as we couldn’t make any solid assumptions as to where exactly the robot would be when seeing the thick black ramp line, not to mention it didn’t always follow the line correctly past the Y-section to begin with.
|
|
|
|
|
|
In an attempt to follow the black line more precisely for more reliable results, we decided to implement a proper PID LineFollower. Based slightly on our Sejway.java code from our previous PID balancing robot, PIDGod.java was made.
|
|
In an attempt to follow the black line more precisely for more reliable results, we decided to implement a proper PID LineFollower. Based slightly on our **_Sejway.java_** [TODO ref] code from our previous PID balancing robot, **_PIDGod.java_** [TODO ref] was made.
|
|
|
|
|
|
After experimenting for a long time with the P, I and D variables based on past experiences we arrived at the values *targetPower *= 60, P = 5, I = 0,4 and D = 8. We dampened the integral error by multiplying by ⅔ every run to prevent it accumulating indefinitely. This PID line follower followed the black line incredibly smoothly, even around the sharp corners of the tape at the top of the ramps, and as such gave us a much stronger foundation for handling our turns.
|
|
After experimenting for a long time with the P, I and D variables based on past experiences we arrived at the values *targetPower *= 60, P = 5, I = 0,4 and D = 8. We dampened the integral error by multiplying by ⅔ every run to prevent it accumulating indefinitely. This PID line follower followed the black line incredibly smoothly, even around the sharp corners of the tape at the top of the ramps, and as such gave us a much stronger foundation for handling our turns.
|
|
|
|
|
|
However, a new problem arose. The robot would go crazy when hitting the intersection at the Y-sections, due to the sudden unexpected values read by both sensors, since there are two black lines going in separate directions. The results were a completely unpredictable robot flying in every and all directions when hitting the intersection due to it’s powerful attempts at correcting the sudden big error values being read.
|
|
However, a new problem arose. The robot would go crazy when hitting the intersection at the Y-sections, due to the sudden unexpected values read by both sensors, since there are two black lines going in separate directions. The results were a completely unpredictable robot flying in every and all directions when hitting the intersection due to it’s powerful attempts at correcting the sudden big error values being read.
|
|
|
|
|
|
To solve this problem, we decided to use it to our advantage. The wild behavior exhibited by the robot clearly indicated the sensors reading values they otherwise never would. In this case, since the robot followed the line very reliably centered, it would always enter the Y-section in a way that both sensors were reading black (or very close to black). We simply did a check for both sensors reading black, and when this happened, we wanted to turn. Now that we could check for a turn on the exact Y intersection, finding the next line became much easier. We just had the robot drive forward a very short distance, and then rotate right until the right sensor read black (it hit the black line going up the next ramp), and then continue its line following up the ramp. The same method was used for the second platform’s turn, although we had to adjust the values for what was acceptable to be considered ‘black’ on both sensor for it to trigger the turn, as the intersection was slightly differently skewed on the second ramp, causing a different pattern of sensor values compared to the first platform. This implementation worked extremely well, and the robot would now very reliably drive all the way to the top of the track, while now also cutting off some time by not having to drive all the way to the back of the platforms. As for turning around the robot on the top platform, we switched to using the Tacho counter to reliably turn exactly 180 degrees. We experimented in a separate program for a while to figure out which values equated to a 180 degree turn, and ended up with a tacho value of 385 working well.
|
|
To solve this problem, we decided to use it to our advantage. The wild behavior exhibited by the robot clearly indicated the sensors reading values they otherwise never would. In this case, since the robot followed the line very reliably centered, it would always enter the Y-section in a way that both sensors were reading black (or very close to black). We simply did a check for both sensors reading black, and when this happened, we wanted to turn. Now that we could check for a turn on the exact Y intersection, finding the next line became much easier. We just had the robot drive forward a very short distance, and then rotate right until the right sensor read black (it hit the black line going up the next ramp), and then continue its line following up the ramp.
|
|
|
|
|
|
|
|
[TODO: Camilla, Insert code from **_PIDGod.java_**, linje 127-133 - husk ref!!]
|
|
|
|
|
|
|
|
The same method was used for the second platform’s turn, although we had to adjust the values for what was acceptable to be considered ‘black’ on both sensor for it to trigger the turn, as the intersection was slightly differently skewed on the second ramp, causing a different pattern of sensor values compared to the first platform. This implementation worked extremely well, and the robot would now very reliably drive all the way to the top of the track, while now also cutting off some time by not having to drive all the way to the back of the platforms. As for turning around the robot on the top platform, we switched to using the Tacho counter to reliably turn exactly 180 degrees. We experimented in a separate program for a while to figure out which values equated to a 180 degree turn, and ended up with a tacho value of 385 working well.
|
|
|
|
|
|
The turns mostly worked fine on the way down as well, although the robot would not follow the line as reliably down the ramps as it did up. The reduced power needed because of gravity meant the robot would correct too much at times, and we tried to remedy this by changing our PID variables once the top of the track was hit. After much experimentation, we arrived at the variables P = 5, I = 0.5, d = 15. Additionally, we started limiting the motor power by cutting the final power variable down to 80, if it was above 80. This eliminated the situations where the robot would reconfigure its power too strongly, and completely lose control.
|
|
The turns mostly worked fine on the way down as well, although the robot would not follow the line as reliably down the ramps as it did up. The reduced power needed because of gravity meant the robot would correct too much at times, and we tried to remedy this by changing our PID variables once the top of the track was hit. After much experimentation, we arrived at the variables P = 5, I = 0.5, d = 15. Additionally, we started limiting the motor power by cutting the final power variable down to 80, if it was above 80. This eliminated the situations where the robot would reconfigure its power too strongly, and completely lose control.
|
|
|
|
|
... | @@ -264,29 +250,37 @@ We spent a long time fiddling with these triggers, but weren’t able to ever ge |
... | @@ -264,29 +250,37 @@ We spent a long time fiddling with these triggers, but weren’t able to ever ge |
|
|
|
|
|
### PID LineFollower with tacho counter in turns
|
|
### PID LineFollower with tacho counter in turns
|
|
|
|
|
|
In an attempt to slow down as little as possible while following a line, we tried to build a robot that takes advantage of having two light sensors and their relative position known to us. Having two light sensors makes it possible for us to know whether we are to the left or to the right of the line we’re following. Partially knowing our position (or at least which side of the line we’re on) means that we can use the integral part of a PID controller well, since that enables us to drive smoothly in a (sine) curve instead of the erratic behavior, we get from reacting everytime we sense black. Currently it only uses the integral part of PID, since that’s the place we thought that the robot would benefit the most from. The robot remembers, which sensor saw black the last and decreases the power of the respective motor exponentially until it sees black again. This way we can have both motors running with a lot of power continuously. A very naive implementation worked pretty well, and it didn’t seem to benefit a lot from more advanced techniques, but that might have something to do with the light in the room, since the readings became more unstable. An improvement we tried to make was to note how many reading of black a sensor made and decrease the turn rate proportionally with the amount of readings, since we want the turns to be as smooth as possible when we are close to following the direction of the line. This change hasn’t improved anything so far, but some calibration might help. This robot reached the second plateau a couple of times without any turning mechanism, because it was lucky and avoided the black tape ‘cross’. Maybe it can be improved to deterministically avoid the cross, but we haven’t looked into that yet. Another way to handle the plateaus could be to determine or identify that the robot has reached one and then do a hard-coded turn each time. This could be done eg. with the tachometer.
|
|
As an alternative to the above approach, which was beginning to seem complex, we began simultaneous work on a more simple approach with the additional intention of focusing more on the track completion time.
|
|
|
|
|
|
|
|
The two light sensors’ only purpose in this robot was to make sure we knew on which side of the robot the line was. We took advantage of their relative positions, by keeping a state of which sensor last saw the black line. Partially knowing our position (or at least which side of the line we’re on) means that we can use the integral part of a PID controller well, since that enables us to drive smoothly in a (sine) curve instead of the erratic behavior, we get from reacting every time we sense black. It mainly uses the integral and the proportional part of PID, since that’s the parts we thought that the robot would benefit the most from. The robot remembers, which sensor saw black the last and decreases the power of the respective motor exponentially until it sees black again. This way we can have both motors running with a lot of power continuously. A very naive implementation worked pretty well, and it didn’t seem to benefit a lot from more advanced techniques, but that might have something to do with the light in the room, since the readings became more unstable. An improvement we tried to make was to note how many reading of black a sensor made and decrease the turn rate proportionally with the amount of readings, since we want the turns to be as smooth as possible when we are close to following the direction of the line. This change didn’t appear to improve anything from the testing we did. Another approach was to introduce more states so that we react while sensing black as well, where the simple robot only start turning after sensing black. This worked alright most of the time, but it made the robot a lot more complex without that much to show for it. Due to that, we continued with the simple implementation, since time definitely was an issue for us at this point of time. This simple robot reached the second plateau a couple of times without any turning mechanism, mainly because it was lucky and avoided the black tape ‘cross’. An improvement we considered was to deterministically avoid the cross, but we didn’t look into that due to lack of time. What we ended up doing was to approximate what the tachometer would read at different plateaus. The turns were approximated and hard-coded as well. This took a lot of tuning and calibration, but made us reach the top relatively easily. Getting down never happened, since the light readings (especially going down) became very unstable at night. Considering our experiences driving up to the top, getting back down wouldn’t take that much effort, since we already had experience in driving down. This robot is implemented in the program **_PIDTest.java_**. The program runs a loop with a sampling time of a few ms. In each sample, it first checks whether the tachometer is above the threshold on which it is supposed to do something, and accordingly does exactly that and otherwise drives using LineFollower functionality. The thresholds are approximated from observations and testing. The first turn should happen at approximately 2200 on the tachometer, which is supposed to be when the robot hits the first plateau. The next threshold is a bit different according to new approximations stemming from observation and testing. As mentioned, this works all the way to the top when the stars align. The LineFollowing functionality works by taking a light reading on each light sensor. These readings lead into different cases, where the previous state is taking into consideration as well. An improvement to this implementation could be to separate the functionality into behaviors, such as LineFollowing and Turning, with an arbitrator, since it could be useful to have the light sensing running, while a hard-coded turn was happening. This way the robot would know where to look for the line after a turn. The robot drove fairly fast and did reach the top every once in a while, but the approximations combined with external factors such as battery power affecting the motor speeds, made it increasingly unstable the further on the ramp it got.
|
|
|
|
|
|
|
|
[TODO EMIL kodespecifikt afsnit - tacho counter, pid, behavior as improvement, so that we knew where the line is while turning eg]
|
|
|
|
|
|
### Introducing DifferentialPilot
|
|
### Introducing DifferentialPilot
|
|
|
|
|
|
Since we had so much trouble getting the robot to turn correctly on the platform by following a line, we decided to also try a different approach using the LeJOS class DifferentialPilot. At first, we made an implementation, CantTouchThis, that did not attempt to follow the line at all, but simply drove straight ahead until reading black on both sensors (i.e. reaching the end of a platform) at which point it perform a turn using the following sequence of commands:
|
|
Since we had so much trouble getting the robot to turn correctly on the platform by following a line, we decided to also try a different approach using the LeJOS class DifferentialPilot. At first, we made an implementation, **_SimplePilot.java_** [TODO ref], that did not attempt to follow the line at all, but simply drove straight ahead until reading black on both sensors (i.e. reaching the end of a platform) at which point it perform a turn using the following sequence of commands:
|
|
|
|
|
|
1. stop (pilot.stop();)
|
|
1. stop (**_pilot.stop();_**)
|
|
|
|
|
|
2. back up 10 cm (pilot.travel(-100);)
|
|
2. back up 10 cm (**_pilot.travel(-100);_**)
|
|
|
|
|
|
3. turn 90 degrees (pilot.rotate(angle); where angle is originally set to 90 and then multiplied by -1 at each platform in order to switch between turning right and left)
|
|
3. turn 90 degrees (**_pilot.rotate(angle);_** where angle is originally set to 90 and then multiplied by -1 at each platform in order to switch between turning right and left)
|
|
|
|
|
|
4. go forward 40 cm (pilot.travel(400);)
|
|
4. go forward 40 cm (**_pilot.travel(400);_**)
|
|
|
|
|
|
5. turn 90 degrees
|
|
5. turn 90 degrees
|
|
|
|
|
|
6. go straight ahead until next black platform end (pilot.forward();)
|
|
6. go straight ahead until next black platform end (**_pilot.forward();_**)
|
|
|
|
|
|
The turn on the top platform was performed similarly, and on the way down the program simply made the robot turn to the right and topple over the edge onto the starting platform.
|
|
The turn on the top platform was performed similarly, and on the way down the program simply made the robot turn to the right and topple over the edge onto the starting platform.
|
|
|
|
|
|
In most runs, the robot succeeded in passing the second platform onto the third ramp, but would then run into the wall or off the track because it had come too much off course. The turn on the top platform as well as the final turn were therefore tested separately, by commenting out sections of the code and placing the robot appropriately on the track.
|
|
In most runs, the robot succeeded in passing the second platform onto the third ramp, but would then run into the wall or off the track because it had come too much off course. The turn on the top platform as well as the final turn were therefore tested separately, by commenting out sections of the code and placing the robot appropriately on the track.
|
|
|
|
|
|
[TODO: Video fra mandag d. 9. som viser kørsel af CantTouchThis]
|
|
[TODO: Fix to markdown video format]
|
|
|
|
|
|
|
|
https://www.youtube.com/watch?v=EdtbRaXm6NA
|
|
|
|
|
|
|
|
*Video 4: ….*
|
|
|
|
|
|
We had foreseen the issues with keeping the robot going in the right direction and not off the track, as expecting to be able to place the robot completely aligning with the track and not having it diverge from this direction later on is unrealistic in a real world environment: Aside from human motorics not and eye-measuring skills not being precise enough, irregularities in the surface and the tires of the robot, as well as imbalances in the robot’s construction, etc. all introduce drifts in its course.
|
|
We had foreseen the issues with keeping the robot going in the right direction and not off the track, as expecting to be able to place the robot completely aligning with the track and not having it diverge from this direction later on is unrealistic in a real world environment: Aside from human motorics not and eye-measuring skills not being precise enough, irregularities in the surface and the tires of the robot, as well as imbalances in the robot’s construction, etc. all introduce drifts in its course.
|
|
|
|
|
... | @@ -294,53 +288,51 @@ The robot may have had trouble getting safely up the ramps using this approach, |
... | @@ -294,53 +288,51 @@ The robot may have had trouble getting safely up the ramps using this approach, |
|
|
|
|
|
#### Combining line following ramp climbing with piloted platform turns
|
|
#### Combining line following ramp climbing with piloted platform turns
|
|
|
|
|
|
Initially, we included code from GodBot in a copy of CantTouchThis, LiberationBot, to drive the robot up the ramp instead of using pilot.forward(). In the API for DifferentialPilot [ref. til [http://www.lejos.org/nxt/nxj/api/lejos/robotics/navigation/DifferentialPilot.html](http://www.lejos.org/nxt/nxj/api/lejos/robotics/navigation/DifferentialPilot.html)] it is stated that the results of other objects making calls to the motors when DifferentialPilot is in use are unpredictable. We had trouble figuring out how to separate line following control from the differential pilot’s control, to be able to switch between them. Our first attempt was to instantiate the DifferentialPilot within the if-statement that captures the case where the robot reads black on both sensors (TODOQ: Måske kode-eksempel), so that it would only try to run in this isolated case and would be terminated upon exit from the if-statement’s scope. The robot had no trouble getting up the first ramp using line following and individual control of the motors, and it performed the turn on the first platforms - but after this, when exitting the if-statement, the robot started randomly turning and racing around. We spent several hours trying out different approaches to getting the differential pilot to work along with the GodBot line following, but did not succeed.
|
|
Initially, we included code from **_GodBot.java_** [TODO ref] in a copy of **_SimplePilot.java _**[TODO ref], **_PilotedCarLineFollower.java _**[TODO ref], to drive the robot up the ramp instead of using pilot.forward(). In the API for DifferentialPilot [TODO ref. til [http://www.lejos.org/nxt/nxj/api/lejos/robotics/navigation/DifferentialPilot.html](http://www.lejos.org/nxt/nxj/api/lejos/robotics/navigation/DifferentialPilot.html)] it is stated that the results of other objects making calls to the motors when DifferentialPilot is in use are unpredictable. We had trouble figuring out how to separate line following control from the differential pilot’s control, to be able to switch between them. Our first attempt was to instantiate the DifferentialPilot within the if-statement that captures the case where the robot reads black on both sensors, so that it would only try to run in this isolated case and would be terminated upon exit from the if-statement’s scope. The robot had no trouble getting up the first ramp using line following and individual control of the motors, and it performed the turn on the first platforms - but after this, when exiting the if-statement, the robot started randomly turning and racing around. We spent several hours trying out different approaches to getting the differential pilot to work along with the GodBot line following, but did not succeed.
|
|
|
|
|
|
##### DifferentialPilot line following (unsuccessful)
|
|
##### DifferentialPilot line following (unsuccessful)
|
|
|
|
|
|
Deciding to take a break from attempting the combined approach, we resorted to implementing line following using the DifferentialPilot’s arc-method, in the class SimpleLibBot.java. It proved difficult to properly steer the robot according to divergence in the black/white readings of the sensors. Though this was perhaps most likely due to a limited overview of how to utilize our error measurements in the arguments to arc() and/or increasing tiredness and frustration levels, we decided to give up on creating a satisfactory implementation. Had we decided to continue, a PID-implementation of DifferentialPilot line following would most likely have proven to work far better.
|
|
Deciding to take a break from attempting the combined approach, we resorted to implementing line following using the DifferentialPilot’s arc-method, in the class **_Piloted_****_LineFollower_****_.java _**[TODO ref]. It proved difficult to properly steer the robot according to divergence in the black/white readings of the sensors. Though this was perhaps most likely due to a limited overview of how to utilize our error measurements in the arguments to **_arc()_** and/or increasing tiredness and frustration levels, we temporarily gave up on creating a satisfactory implementation. Instead, we began an implementation using a switcher to switch between behaviors implemented in an interface. This is described in the section below. After some debate regarding this solution (to be found in the section below), we continued the attempt at implementing line following using DifferentialPilot. We experimented with different parameters for **_arc()_** and introduced a turn utilizing **_rotateRight()_** to turn until aligned with the bottom bar of the Y on the platform in order to let the robot more easily find its way back on track after making a platform turn. We also performed other minor additions. We managed to get the robot to the second platform, successfully performing the intermediate turn operation on the first platform [TODO: Video]. At some point, however, the robot began failing in detecting the black end line - perhaps due to poor lighting in the later hours of the day, perhaps due to the sensors being raised as they were sometimes scraping on the track, and perhaps simply due to low battery. As black sensing was still working for the other two ongoing implementations, we decided to leave the DifferentialPilot at this.
|
|
|
|
|
|
[TODOQ (til Ida): nyt forsøg på kombination vha. interface mv.]
|
|
|
|
|
|
|
|
##### Using a bumper
|
|
##### Switching between navigation types
|
|
|
|
|
|
An implementation similar to CantTouchThis.java, that used a touch sensor to detect when the robot hit the wall by the track *and then* making the second 90 degree turn, was also made (FRIse.java), but was never tested. To test it, we would have to refit the robot with a touch sensor, preferably with a bumper to ensure that collision with the wall would be detected no matter the angle of the robot. Since the difference to using CantTouchThis seemed minor and we figured that this version would take longer to complete the track due to having to wait until hitting the wall and then backing up, we decided to postpone refitting with a touch sensor until we might see an actual gain in using one. We never got to this point. A benefit we might have seen would be the possibility of letting the robot use the bumper to align with the wall, by waiting a little before stopping upon impact, thus enabling it to enter the next ramp perpendicularly after making the 90 degree turn following collision.
|
|
We constructed an architecture with a class, **_Switcher.java_** with a field variable of the interface type **_NavigatingRobot.java_**, initially instantiated as a **_PilotedBot.java_** which was intended to navigate using DifferentialPilot. The class **_SensorSteeringBot.java_** implements line following similar to that of GodBot.java. The idea was then to switch between a PilotedBot instance and a SensorSteeringBot instance on different triggers, such as reading black on both sensors. We never finished implementing this idea: It dawned on us that this was very similar to using an arbiter, and upon investigating how to implement it using an arbiter, we reached the conclusion that we were not certain that this would free us from the trouble of combining the individual motor control of Car with DifferentialPilot. We therefore went back to attempting to implement line following, now with a fresh mindset (as the arbiter discussion took place in the beginning of our session on Monday the 9th of May).
|
|
|
|
|
|
[TODOQ (til Ida): rename CantTouchThis, FRIse og LiberationBot]
|
|
##### Using a bumper
|
|
|
|
|
|
### Andre noter (ingen fast plads i rapporten endnu)
|
|
An implementation similar to **_SimplePilot.java_** [TODO ref], that used a touch sensor to detect when the robot hit the wall by the track *and then* making the second 90 degree turn, was also made (**_PilotWithBumper.java _**[TODO ref]), but was never tested. To test it, we would have to refit the robot with a touch sensor, preferably with a bumper to ensure that collision with the wall would be detected no matter the angle of the robot. Since the difference to using SimplePilot seemed minor and we figured that this version would take longer to complete the track due to having to wait until hitting the wall and then backing up, we decided to postpone refitting with a touch sensor until we might see an actual gain in using one. We never got to this point. A benefit we might have seen would be the possibility of letting the robot use the bumper to align with the wall, by waiting a little before stopping upon impact, thus enabling it to enter the next ramp perpendicularly after making the 90 degree turn following collision.
|
|
|
|
|
|
OBS skriv om: ville nok være bedre at have behaviors og at håndtere dem så én behavior kører færdig, før en behavior med lavere prioritet kan overtage (lige nu kører vi på if-statements og er derfor nødt til at sleepe, mens vi drejer 180 grader, så den ikke bliver fucket op af at læse hvid undervejs i drejet)
|
|
### Discussion of alternative approaches
|
|
|
|
|
|
Idea for going even faster: gearing
|
|
Several times during the work of this lab session we planned to use behaviors and an arbiter to separate each behavior from each other. Instead we used very long clase
|
|
|
|
|
|
Idé til torsdag d. 5. maj: brug ultralydssensor til at måle afstanden til platformen og dermed til at se, om robotten er på vej over en platform-kant.
|
|
TODOQ: ville nok være bedre at have behaviors og at håndtere dem så én behavior kører færdig, før en behavior med lavere prioritet kan overtage (lige nu kører vi på if-statements og er derfor nødt til at sleepe, mens vi drejer 180 grader, så den ikke bliver fucket op af at læse hvid undervejs i drejet)
|
|
|
|
|
|
Brug evt. tacho counter til at dreje.
|
|
Furthermore, we discussed using an ultrasound sensor mounted to the front of the robot, facing down, as a means of discovering when the robot was hitting a platform,
|
|
|
|
|
|
Random fra torsdag d. 5. maj:
|
|
TODOQ: brug ultralydssensor til at måle afstanden til platformen og dermed til at se, om robotten er på vej over en platform-kant.
|
|
|
|
|
|
Switched back to GodCar (efter at have opgivet at kombinere line following med DifferentialPilot, red.), attempting to replace hard coded milisecond turns into using the tacho counter for more reliable turns.
|
|
## **Conclusion**
|
|
|
|
|
|
Attempting to implement PID controller with I and D part to follow line more smoothly, for less inconsistent angle entries into the black line.
|
|
As we haven’t succeeded in building a robot that autonomously drives up and down the track, we can’t say that we have accomplished the overall goal. That said, we have implemented three different attempts that all seem promising in their own way.
|
|
|
|
|
|
## **Conclusion**
|
|
We ended up having to work for more than the two days originally planned. We worked for a total of three days, on getting the robot to climb and descent the track. We spent a total of 30 hours, spread over 7 hours on the 28th of April, 9 hours on the 5th of April and 9 hours on Monday the 9th of April.
|
|
|
|
|
|
TODO: Overall success
|
|
At the 5th of April we decided to split the group into working with two different approaches to a PID line follower, and another using the DifferentialPilot. One PID follower focused on very precise line following for predictable light sensor readings when encountering the Y-sections to trigger the turns on the platforms, whereas the other used a simple idea of which side of the line the robot was on, whilst using the tacho counter to handle the turns on the platform.
|
|
|
|
|
|
We ended up having to work for more than the two days originally planned. We worked for a total of three days, on getting the robot to climb and descent the track. We spent a total of TODO hours, spread over 7 hours on the 28th of April, 9 hours on the 5th of April and TODO hours on Monday the 9th of April.
|
|
The precision line follower, **_PIDGod.java _**[TODO ref], had a lot of success getting to the top of the platform, and once we raised the light sensors were able to drive down as well, but the problems caused by the raised sensors reading black from being too far off the ground when driving onto the platforms while driving up the track, meant we were never able to get a reliable reaction to all of our desired turning triggers, and could never get it to drive up and down in a singular build and program.
|
|
|
|
|
|
TODOQ: Konklusion på line following og PID - Emil og Nicolai
|
|
TODOQ: Konklusion på line following og PID - Emil]
|
|
|
|
|
|
Our attempt to use the **DifferentialPilot** class was illustrative of the inconsistencies that the real world brings into robot programming; although **DifferentialPilot** is very effective at controlling the robot’s movements precisely, it is not enough to make a functioning hill-climbing robot as external factors bring the robot off a perfectly straight course.
|
|
Our attempt to use the **_DifferentialPilot_** class was illustrative of the inconsistencies that the real world brings into robot programming; although **_DifferentialPilot_** is very effective at controlling the robot’s movements precisely, the simple approach in **_SimplePilot.java_** is not enough to make a functioning hill-climbing robot as external factors bring the robot off a perfectly straight course. The work on **_PilotedLineFollower.java_**, which adds line following to SimplePilot, showed promise, but due to time constraints we chose to opt out of our experiments with it before having implemented a fully functional up-down robot.
|
|
|
|
|
|
[TODOQ: line following med DifferentialPilot - Ida og Camilla]
|
|
Using **_DifferentialPilot_** was different from the other approaches that we have tried during the course, as **_DifferentialPilot_** provides us with methods that utilize calculations based on tacho count and physical parameters (i.e. wheel diameter and distance). These calculations are far more precise than the ones we have attempted to do using light measurements and time (e.g. **_sleep(1000);_**), and even if we had used the tacho count, we would have had to spend a very long time finding out how to turn e.g. 90 degrees given our robot’s construction. Thus, **_DifferentialPilot_** relieves us of some basic but important calculations.
|
|
|
|
|
|
Using **DifferentialPilot** was different from the other approaches that we have tried during the course, as **DifferentialPilot** provides us with methods that utilize calculations based on tacho count and physical parameters (i.e. wheel diameter and distance). These calculations are far more precise than the ones we have attempted to do using light measurements and time (e.g. **sleep(1000)****;**), and even if we had used the tacho count, we would have had to spend a very long time finding out how to turn e.g. 90 degrees given our robot’s construction. Thus, **DifferentialPilot** relieves us of some basic but important calculations.
|
|
Looking back on the progression of our work in this lesson, we would probably have benefitted from (re-) joining forces a lot earlier; while splitting up and letting people unfold creative ideas on their own provided some interesting and useful insights, these were not utilized very well. Should we decide to split the work between us again, we expect to benefit from joining up after a set amount of time and present our findings, before deciding on one approach to continue working on together.
|
|
|
|
|
|
Lack of (video) documentation has been a recurring theme in this report - and a mistake in our experimentation work. We should have documented our experiments better, and we have learned from while in writing the report. To not make our video documentation seem unmanageable, perhaps we should consider re-introducing the use of title post-its, as in Lesson 5 (this was actually suggested on the first lab session of this Lesson, but for some reason we did not elect to do it).
|
|
Lack of (video) documentation has been a recurring theme in this report - and a mistake in our experimentation work. We should have documented our experiments better, and we have learned from while in writing the report. To not make our video documentation seem unmanageable, perhaps we should consider re-introducing the use of title post-its, as in Lesson 5 (this was actually suggested on the first lab session of this Lesson, but for some reason we did not elect to do it).
|
|
|
|
|
|
TODOQ: Samlet konklusion
|
|
All in all we are satisfied with the work done during this lab-week, but disappointed that we didn’t reach the goal of implementing an autonomous track-climbing robot.
|
|
|
|
|
|
## **References**
|
|
## **References**
|
|
|
|
|
... | @@ -352,13 +344,25 @@ TODO |
... | @@ -352,13 +344,25 @@ TODO |
|
|
|
|
|
[3] Fred G. Martin, Robotic Explorations: A Hands-on Introduction to Engineering, Prentice Hall, 2001.
|
|
[3] Fred G. Martin, Robotic Explorations: A Hands-on Introduction to Engineering, Prentice Hall, 2001.
|
|
|
|
|
|
|
|
[4]
|
|
|
|
|
|
|
|
[5]
|
|
|
|
|
|
|
|
[6]
|
|
|
|
|
|
|
|
[7]
|
|
|
|
|
|
|
|
[8]
|
|
|
|
|
|
|
|
[9]
|
|
|
|
|
|
## **Appendix A: Unconstrained idea generation**
|
|
## **Appendix A: Unconstrained idea generation**
|
|
|
|
|
|
In the experiments with the faster initial ramp climb, where we had the robot simply race up the track, it was suggested that we give the robot "arms" to allow it to hold onto the sides of the ramp while going up. This way, the robot would be prevented from running off the track. However, we foresaw an abundance of issues with raising the arms before reaching the platform, and doing so in time. The idea is illustrated in Figure TODO-x.
|
|
In the experiments with the faster initial ramp climb, where we had the robot simply race up the track, it was suggested that we give the robot "arms" to allow it to hold onto the sides of the ramp while going up. This way, the robot would be prevented from running off the track. However, we foresaw an abundance of issues with raising the arms before reaching the platform, and doing so in time. The idea is illustrated in Figure 6.
|
|
|
|
|
|
![image alt text](image_0.png)![image alt text](image_1.png)
|
|
![image alt text](image_0.png)![image alt text](image_1.png)
|
|
|
|
|
|
*Figure TODO-x: The robot (Frej) with arms extending below the track to keep Frej in place.*
|
|
*Figure 6: The robot (Frej) with arms extending below the track to keep Frej in place.*
|
|
|
|
|
|
Another idea along the same lines involved extendable arms to reach for the second platform and pull the robot from the starting area. This led to the even more unrealistic suggestion of letting the robot throw a grappling hook at hoist itself to the second platform.
|
|
Another idea along the same lines involved extendable arms to reach for the second platform and pull the robot from the starting area. This led to the even more unrealistic suggestion of letting the robot throw a grappling hook at hoist itself to the second platform.
|
|
|
|
|
... | | ... | |