tirsdag den 19. august 2014

Conclusion on End Course Project

Conclusion on end course project

Through 10 sessions we have been working on making an autonomous car balance on a tube, while a remotely controlled car inside the tube is able to dictate the direction the tube is moving. We were successful at obtaining this goal. However the car balancing on top of the tube is susceptible to gyroscopic drift, despite our best attempts to counteract it. This limits the amount of time the balancing car can stay on top of the tube to a few minutes, at our best runs. We have done extensive work to reduce the drift, and have produced a complementary filter which seems very promising to counteract the gyro drift, but we lack the time to produce a proper implementation of said filter into our balancing car code. We are hopeful, that if pursued, we would be able to enhance the performance of the balancing car by logging and analyzing the data from the tube balancing car, similar to what was done in session 10.

Future work:

  • Tests and tweaks on the implemented version of the complementary.
    • // Alternative do further research on the EMAOFFSET from session 9.
  • Fine-tuning of PID parameters, maybe through Ziegler Nichols method.
  • Make more tests investigating how different power values, using setPower(), impacts the gyro sensor readings.
  • Mount caterpillar tracks on the car inside the tube, this should make the car stronger, and it’s movement smoother.
  • Experiment with different tubes. Heavier tubes mainly. A transparent tube would be desirable for aesthetics as well.  

All code from the project can be found here:

  • Code: github.com/banditlev/TubeBalancerProject.git

Final Project - Lesson 10

Session 10

Date: 18/06 2014
Duration of activity: 9.15 - 16.00
Group members participating: Pætur Askildsen, Christian Jegstrup Hansen, Søren Gregersen, Søren Ditlev and Alexander Rasmussen


Goal

Test and fine tune the complimentary filter

Plan

Use a data logger to produce logs for the gyro, accelerometer and filter with time stamps. Use Excel to graph the logged data and analyze it.   

Result

Logging the complimentary filter

All test are performed the same way. The car is placed on the tube and held steady by hand. The car is then moved 1x forward, 1x backward, 3x forward, 1x backward and held steady for a few seconds. See picture below:

Figure 1 :  The test setup

Log 1:
Figure 2
As is visible from figure 2  the filter(orange) seems to work. The gyro(blue) drift over time whereas the filter seems to stay roughly around zero. However there are a few things to notice about the accelerometer(purple). It is centered around the middle and fluctuate very little. This is unexpected as accelerometer should be very sensitive. The solution we were able to come up with is that because the accelerometer is moved in a circular motion as opposed to a straight line (see figure 3 ). This drastically reduced the amount of force that affects the accelerometer hence the low fluctuation. This is not a bad thing however since accelerometer reading stay around zero and therefore help keep filter in check ie. not drifting like the gyroscope. We also noticed that the accelerometer offset is slightly off (2 degrees too high) and that the accelerometer readings is actually inverted. This can be seen as the accelerometer goes up when the gyro goes down and vise versa.  

Figure 3: Accelerometer reading -  difference between segway and tube balancer.


Log 2:
Figure 4

Here we made changes to the accelerometer, we inverted the axis to be correct and changed the offset, but since we inverted the axis we accidently moved the offset two degrees the wrong way meaning that it was even more displaced than in iteration 1.

Log 3:
Figure 5

Again a few more corrections. Accelerometer offset is now correct and we have changed the weight of the gyroscope to 99% and the accelerometer to 1%. The reason behind this operation is simple. First of the gyro is accurate in short term. By making the gyro weight more in the equation the filter will more closely resemble the gyro data(see first iteration compared to third) , in the short term (notice how well the filter curves follows the gyro curves early). Second since the accelerometer’s only purpose is to keep the filter from drifting like the gyro (especially in our case where the accelerometer is just centered around zero).  it makes great sense not to rely on it as much. The accelerometer still serves it purpose, preventing drift, as evident by the last red circle.  

Conclusion

We have done extensive testing with the complementary filter, and succeeded in producing very promising results. However when implemented and used on the tube balancing robot it does not work as stable as when running the filter alone. It is definitely possible to get it to work, but will need some more testing and changing of parameters to work better.

Final Project - Lesson 9

Session 9

Date: 16/06 2014
Duration of activity: 9.15 - 15.30
Group members participating: Pætur Askildsen, Christian Jegstrup Hansen, Søren Gregersen, Søren Ditlev and Alexander Rasmussen


Goal

  • Work on minimizing gyro drift.
  • Make the robot balance even more steadily.

Plan

Results

Work on gyro drift so far

To sum up, we have found that the gyro sensor readings for the HiTechnic NGY1044 gyro sensor are affected by changes in input voltage, which happens when the motors are turned on [1][2][3]. Kirk Thomson seems to be the first one to notice this in 2007 [3], when he was building a Gyro class, probably the one we use in our project as he is co-author of that one [4]. Everything was working fine for Thompson until he coded to also run a motor with a PID-controller together with the gyroscope. He found that his gyro angle integrator would drift after setSpeed() was called: “The sensor value (from the ADC) changes by 2 after setSpeed() is called”. He therefore advises to: “The solution was to recalc the bias [gyro sensor offset, red.] after setSpeed(0) was called” [3].
We, however, do not use the same setSpeed() method as Thompson does because LeJOS motor classes has changed since 2007. Which motor should we use? We do not want a regulated motor because under LeJOS motor tutorial under the headline ‘When might you want to turn off speed regulation?’ [4] it states that if speed corrections happen frequently, like in a line follower or a balancing robot, there is no advantage in the regulator thread which tries to keep the speed constant. Instead an unregulated motor could be used, creating an instance of the NXTMotor class, for example:
NXTMotor m1 = new NXTMotor(MotorPort.A);
This is exactly what we do, as we work with a balancing robot, where corrections happen frequently and the speed should not be constant.
We rewrote Ole Caprani’s Car class [6] to a TubeCar class using the NXTMotor class, see figure 1. NXTMotor class does not have a setSpeed() method but a setPower() method. We made a test to see if setPower(0) changes the gyro sensor value readings in the same way, by 2, as setSpeed(0) by finding code inspiration in Thompson initial test [3]. We made a test program, and found that setPower(0) like setSpeed(0) causes the gyro sensor reading to drop by 2, using a DataLogger class, see figure 2 for a graph of the test results of the DataLogger illustrating the gyro sensor readings drop by 2. See figure 3 for Thompson’s modified test class. The random fluctuations away from 591, before the method call, and 589 after the method call is caused by the fact that the offset of a gyro will vary a bit over time, which is called random walk or drift [1].

Figure 1: TubeCar.java which we use in our tube-balancing car.



Figure 2: A test made which shows, that setPower(0) actually causes a drop in gyro sensor readings by approximately 2 (from 591 to 589), making it the right method to call before gyro sensor offset calibration.

Figure 3:
The program used to test if setPower(0) affects raw gyro sensor readings. Start program, wait a few seconds, hit and hold the enter button for a short moment to ensure that the if-loop is called (as the thread is set to sleep sometimes), wait the same amount of seconds, and hit escape to stop logging the data. To avoid the need to hold the enter button to ensure that it is registered that it has been pressed, we could have used a ButtonListener [7], which: “ [...] is used to detect when a button is pressed, whatever your program is doing at the time” but it was not deemed necessary time-wise to implement for this test as long as we are aware of the fact, that you have to hold the enter button for a little while.

If the gyro sensor readings drop by 2 when setPower(0) is called, is the same constant drop of 2 noticed when setPower(10) or setPower(50) instead is called? We tried this out, changing the setPower(0) to setPower(50). The results can be seen in figure 4 below. Before calling setPower(50) the gyro sensor value is around 591 with some random walk. But after setPower(50) is called it is very difficult to get a good reading, because setPower() sets and applies the power to the motors, where the vibrations from the motors running causes the oscillations seen after setPower(50) is called even though we tried to lay the car where the wheels could spin in free air.

Figure 4:  A test which is unable to show if setPower(50) like setPower(0) causes a drop in gyro sensor readings by approximately 2 (from 591 to 589).

Therefore we tried a third test where we set the power to 20 so it is different from 0 but the motors wont run. It seems that instead of a drop of 2 from 591 to 589 it drops more often to 590, by 1. But it seems not to be significant, since it also drops to 589 sometimes. We stop making tests here of time considerations. Future work would be to log gyro sensor reading drops for different setPower() values and make regression on this to maybe have a formula to try out use for adjusting the offset, if gyro sensor drop is found to not be constant of 2.
Figure 5: A test to show if setPower(20) causes a drop in gyro sensor readings by 2.

Another trick to avoid the changing gyro sensor offset as a result of power drops, mentioned in [1], is to use a sensor mux with an external power supply, for example like the one from Mindsensors, see figure 6. This way the motor and the gyro gets power from two different sources and thus does not impact each other. We however chose for the sake of simplicity to go with powering the motors and the gyroscope from the same NXT battery, keeping in mind powering on the motors before calibrating and using the gyroscope. In session 1 we mentioned that [1] advices to choose another gyroscope than the HiTechnic, but since other have build balancing robots with the HiTechnic gyroscopes, we still chose to go with those.


Figure 6: This multiplexer can connect any sensor designed for Mindstorms NXT (LEGO and/or third party), upto 4 sensors to one NXT sensor Port, uses External Battery [8].

One of the biggest factors contributing to gyro sensor drift is temperature. When one starts using a sensor, the temperature of the sensor rises, and it gets hotter than the ambient temperature. This results in the offset (the sensor value readings) of the sensor changing [1][9]. Therefore [1] advices to let the sensor warm up before calculating the offset, if you need a very good signal. Even when temperature and power are constant the offset of a gyro will vary a bit over time, as also could be seen in the graph in figure 2, the random walk variation.

Work on reducing gyro drift

As the gyro sensor readings change when they gyro sensor gets hot, we worked on implementing a method they use in the original HTWay NXC code for continuously correcting this drift. We previously turned this off since we thought that it caused more drift. But in this lesson we tried to turn it on again, to give it another try and tweak the value, since the gyro sensor changes readings over time when it gets hot, linearly changing the offset is a need, as mentioned in lesson 4. In the original HiTechnic HTWay code that we used in session 2, they in their comments describe their way for coping with gyro drift [10]:
Screenshot 2014-06-17 13.04.28.png
and they use this constant in:
Screenshot 2014-06-17 13.05.59.png
Where gOffSet is our initial bias / offset value from 100 gyro samples:
Screenshot 2014-06-17 13.07.01.png
The first test we did after implementing the drift regulation in our robot, the robot quickly drifted the opposite way of what we had seen in earlier tests. This let us to believe that the EMAOFFSET value was too high. We then slowly decreased the value, while testing it each time, and ended up with a value of 0.0007.
This implementation still made the sensor drift, but the drift was now slower, and the robot, stayed on the tube for around 30 seconds longer, than what we had achieved before.

Accelerometer slowing motors down

When testing the filter where we also use the accelerometer, we discovered a bug that we have yet to figure out. When the accelerometer is on the reaction time of the balancing robot is very much decreased causing the robot to react slowly thus falling off the tube much quicker than before. When we do not call for accelerometer readings and do calculation on those readings, the motors reacts as quick as before. We think this might be due to the added sensor fetching and sensor value calculations in our control loop causing the loop to take longer to go through resulting in less often motor power and direction commands, resulting in a slower reacting balancing robot.

Continued work on the complementary filter

In session 6 we introduced the complementary filter and the theory behind it. Our initial code from session 6 however did not work as intended, as the angle calculated in the filter did not react fast enough on the gyroscope values.
After doing a little more research on the complementary filter, we found out that our approach to how the accelerometer value is calculated was wrong. Instead of calculating a gravity vector based on readings from two axes as we did in session 6, we found another approach which is described below.
The accData variable in the complementary filter equation is the data from the accelerometer processed according to the following formula:
accData=Math.toDegrees((Math.atan2 (accX, accZ) + Math.PI))-accOffset

In the formula we only worry about getting the result from the y-axis because it is along this axis the robot is moving.
As earlier described the acceleration is measured in three axes, x, y and z. Acceleration is measured in the range of –2g to +2g with scaling of approximately 200 counts per g [4].  To obtain the angular position with the accelerometer, we are going to determine the position of the gravity vector (g-force) which is always visible on the accelerometer.
We can do this by using the method atan2 provided in the Math class. The atan2 method converts the rectangular coordinates (x, y) to polar coordinates (r, theta) and returns the angle theta. By calling the Math.toDegrees() we change the polar coordinates returned by the atan2 function to degrees, so that both the accelerometer data and gyroscope data is calculated in degrees.  
To calibrate the accelerometer to be 0 at the starting point, we subtract a constant, accOffset, from the calculated number. The offset has been found by placing the car on a horizontal surface while reading the accData constant.

Figure 7: The implementation of the complementary filter.

This implementation still turned out to cause a few problems. Or at least it did not work as intended. We are quite sure that the values calculated in the algorithm are correct, but there is still a problem with the angle that the filter returns to the PID controller of the main program. When the filter is tested on the robot without activating the motors it works great. But when the motors are activated it seems that they interrupt the filter.

Conclusion
We have tried to minimize the gyro drift by continuously regulating the offset, but did not get the a satisfying result, since the drift seem to vary a lot in each individual test.  
We have experimented with how activating the motors influence at high power will influence the gyroscope, as previously we concluded that setting motor power to 0 produces a drop of 2 in pure gyro readings. We found that by setting the motor power to 20 the system still produces a small drop in gyro reading (1-2), but that system produces notably more noise at this power level. With the motors at 50 the system was to noise for us to get reliable reading, therefor we will continue use the 2 reading drop in our project, though further test can be done at this area.
We have change the way in which we calculate the reading from the accelerometer, to fit into our complementary filter, theoretically this should produce better result, but it need further testing before we can confirm this.

Plan for next session(s)

Test and fine tune the complimentary filter

References

[3] motor setSpeed() changes AD sensor value, http://www.lejos.org/forum/viewtopic.php?f=7&t=2276
[5] Gyrosensor output changes with motorpower, https://sites.google.com/site/legolabnotebook/end-course-notebook/session-3/session-4
[5] When might you want to turn off speed regulation?, http://www.lejos.org/nxt/nxj/tutorial/MotorTutorial/ControllingMotors.htm#6
[9] http://www.lejos.org/forum/viewtopic.php?f=7&t=4656#p19823

[10] HiTechnic HTWay Version 1.1, http://www.hitechnic.com/upload/786-HTWayC.nxc

Final Project - Lesson 8

Session 8

Date: 13/06 2014
Duration of activity: 9.15 - 15.00
Group members participating: Pætur Askildsen, Christian Jegstrup Hansen, Søren Gregersen, Søren Ditlev and Alexander Rasmussen


Goal

  • Make the car on top of the tube balance more steadily.
  • Reinforce the chassis of the balancing car.
  • Reduce the speed of the car inside the tube.

Plan

The lever handle on the remote controller was not sufficient and therefore we plan to Improve its design.
We plan to rebuild the car inside the tube so that it cannot tilt around.
We plan to reduce the speed of the car inside the tube so the balancing robot can keep up.
We plan to fine-tune the PID parameters.

Results

Reducing the speed of the remote controlled car

The balancing robot had difficulties keeping up with the remote controlled car that is inside the tube and constantly fell off the tube. The remote controlled car had a maximum speed of 100 both forwards and backwards and this had to be reduced, so that the balancing car could keep up with it.

The task to reduce the speed of the car inside the tube was not as easy as presumed. The first solution was to change the values of the field variables SpeedControlMax and SpeedControlMin from 100 and -100 to 75 and -75 respectively. We thought that this would reduce the max speed in both directions to 75 but it made no difference at all. The reason that this did not work is because these two variables in fact does not have anything to do with the speed of the car; they are only used to store tacho counter values during calibration of the remote controller.

Another way to fix this was to make a method called reduceSpeed() that can be seen in figure 1. This method guarantees that the maximum and minimum speed sent from the remote controller to the car inside the tube does not exceed the desired maximum and minimum value. However this method removes the proportional relationship between the minimum/maximum speed and tacho counter of the motor.

Figure 1: Code snippet of the method reduceSpeed()

Because the two other methods did not solve the problem satisfactorily we decided to rethink the way the tacho counter is mapped to speed. Figure 2 shows the old method and the new method to map the tacho counter to speed. Rethinking this mapping was not an easy task because we did not have a proper understanding of the original method to calculate the speed. In the first calculation of the return value (which is the speed) is made into span between 0 and 1 by dividing the speedValue with SpeedControlMax. This span  (0;1) has to be transformed into the span (-maxSpeed; maxSpeed). This generic span makes it possible to easily set the maximum speed of the remote controlled car, which is needed because we do not know what the optimal maxSpeed is for the balancing robot to keep up.
Figure 2: Code snippet of old and new method to calculate speed
from tacho counter of the motor.

The calculations in this new method is first to divide the span (0;1) into two spans (0.0;0.5) and (0.5;1.0), and then to transformate the span the two spans as follows

(0.0;0.5) → (-maxSpeed; 0) and  (0.5;1.0) → (0;maxSpeed)

The first transformation uses the formula:
returnVal = -maxSpeed+maxSpeed*returnVal0.5

While the latter uses the formula:
returnVal =returnVal -0.5(0.5maxSpeed)

In these two formulas the returnVal is the calculated speed. This new method makes it possible to just set a maximum speed and then the remote controlled car will drive with a speed in the range (-maxSpeed;maxSpeed).

While finishing the report we found an easier method to map the values from the tacho counter to speed. This method is a result of wanting to commenting the original method to calculate the speed, which lead to better understanding of it and made it possible to use the same idea. The idea is to multiply the span (0;1) with 200 which results in the span (0;200) and then move the span to (-100;100) by subtracting 100 from both sides of the span. Figure 3 shows the code snippet of an improved version of the original method.

Figure 3: Code snippet of improved version of the original method

In figure 3 the maximum speed is 100, which can be replaced with the variable maxSpeed. The number 200 is twice of 100, which was replaced with maxSpeed, and therefore 200 can be replaced with 2*maxSpeed. When the numbers 100 and 200 are replaced with variables it results in the general method shown in figure 4.

Figure 4: Final method to calculate the speed

Work on the design of the remote control

Before we had the remote controller seen in session 5 figure 4. This remote had a very simple handle and today we tried several designs for handles using different lego bricks.

We finally built the handle in figure 4. This remote has affordance that you are controlling the speed of a wheeled vehicle.

Figure 4: Final design of the remote control

Work on reinforcing the chassis of the balancing car

The balancing car kept falling apart each time it smashed to the ground. To avoid the car falling apart all the time we used some time to reinforce the chassis and exterior of the car.
Figure 5: The chassis of the car has been slightly reinforced to resist all the falling downs from the tube during testing

Fix the design of the car inside the tube so that it cannot tilt around

The remote controlled car was firstly built to drive even though it was upside down. But we experienced that when the car flipped upside down or back again it produced a bump that disturbed the balancing car. This disturbance was too big for the balancing car to keep balancing. Therefore we chose to rebuild the remote controlled car, so that it cannot turn over. Figure 6 below shows on the left the original design of the remote controlled car and on the right the final design where gearing and four extra wheels are added to the car. The gears was added to make the car four wheel driven so it could drive even though it was upside down, this is now redundant since we realized that the car must not flip upside down, and added the the four extra wheels to stop this.

Figure 6: First (to the left) and final design (to the right) of the remote controlled car

Conclusion

We have have successfully managed to reduce the speed of the remote controlled car, even though it took some time. We rebuilt the remote controlled car so that it cannot flip and get the robot on top out of balance. We have also reinforced the chassis off the balancing car, so that it does not fall apart when it smashes to the ground.

Plan for next time


Maybe fine-tune PID parameters even more, perhaps using Ziegler–Nichols method