Project lab 4b - BeamCounter refinement

Date: 04/06/2013
Duration of activity: 09:00-21:00 --> 12 hours
Group members participating: Ole Rasmussen and Kasper Føns

1. Goal

The goal of this activity is to refine the BeamCounter.
We would like our BeamCounter to reliably handle all beam sizes - from a length of two to a length of fifteen. Our current solution does not handle beams of length two or three very well, since they are able to get stuck in the intersections between belts.

2. Plan

Our plan is to look at the conveyor belt design and use available Lego bricks to see if it is possible to adapt it to handle beams of length two and three as well as longer beams. If we succeed in doing so, we would add our light sensing system to the new conveyor belt and add supporting walls so that beams are not able to fall off the conveyor belt system and such that they will always pass the sensors in a straight line. Notice that this project lab was conducted in parallel with project lab 4a.

3. New conveyor belt design

We wanted to test if a new conveyor belt design could alleviate the problem with small beams. We wanted to change the belt from the tank threads (left on Figure 1) to another type of belt (right on Figure 1). The idea is that the new ones are thinner and could potentially reduce the gab between belts and therefore allow smaller beams to cross the intersections.

Figure 1: Old tank conveyor threads on the left (inside-out and normal) and new ones on the right (normal and inside-out). 
By adding our rotating axle to our new conveyor belt design as well (See Figure 2), we are able to transport beams of length two. As can also be seen in Figure 2, the gaps are much smaller compared to the ones seen in our preliminary experiments, here reproduced as Figure 3.
Figure 2: Rotating Axle added to our system so that it supports beams of length two.
Figure 3: Old conveyor belt design. There is a much larger gap between intersections.
Our system is driven by two motors, since this system has more friction because the belts are tighter. Our gearing system can be seen in Figure 4 and 5. The Figures shows an intersection of two belts. On both belts an axle is connected to a z24 gear. When driving the gear, the belt is driven forward. The two gears are connected with a z8 gear, so that driving one of the belts drives them both. The axle on top is then connected with the z8 gear. The axle is thus rotating three times (24/8=3) as fast as the belts. The motors are driven by using NXTRegulatedMotor.forward() and in a sense is a very simple open-loop control [1].

Figure 4: Gearing system for driving conveyor belt and rotating axle. The intersection of the belts is just below the axle.
Figure 5: Gearing system close up. The two z24 gears are connected by a z8 gear. The axle that has the z8 gear is also connected to the rotating axle by another z8gear and a small flywheel type gear.

4. Adding light sensors

We used a new design for holding the belts. In our preliminary design we used Lego beams, but our new design uses normal Lego bricks. This allows us to easier build walls around the track to make sure that our lightsensors would be able to count the holes correctly. Our design can be seen in Figure 6.
Figure 6: Our new design using standard Lego bricks for outer design and new conveyor belt types.
There were no walls where we had located our sensors and this presented a new problem. Larger beams would easily pass our sensors since they were supported by the walls in both ends as in Figure 7. However, smaller beams could become stuck as in Figure 8. Our solution to the problem was to add small "windows" for our lightensors. This allowed us to support the bricks while being able to count the holes. A brick passing by the windows can be seen in Figure 9.

Figure 7: Larger beams are supported by walls while going through our sensing platform.

Figure 8. Smaller beams are not supported and can get stuck like above.

Figure 9. Added support walls with windows allowing  light to pass through but still having beams supported.

5. Program source code

At this point our BeamCounter code is pretty stable and we will here explain how our counter program works. Below is our source code for the counter.
It uses two sensors, one to emit a light ray (the floodLight) and one to sense if it is being broken by a brick (the sensor . It also uses a BeltDrive instance, which is an encapsulation of one or multiple NXTRegulatedMotors, which can be asked to drive the belt forward. The BeltDrive class then knows which motors to run and in which direction for all motors to drive the belt the same way.

When the BeamCounter is instantiated it will setup the lightsensors and wait for the receiving sensor to sense the light from the sending sensor. If we don't do this the BeamCounter could register a beam hole at the moment it starts, since it takes a small amount of time for the floodlight to actually light up.

Our Run() method starts the beltDrive and begins sampling the sensor. We sense each time the lightbeam is broken and for a brick of length n, it will be broken exactly n+1 times. We play a small sound for each hole we count (excluding the first time the lightbeam is broken to account for the +1 term). When the light beam has not been broken for BRICK_END_TIME_THRESHOLD_IN_MS time, we believe the brick has ended and write to the screen how many holes were found.

 import lejos.nxt.LCD; 
 import lejos.nxt.LightSensor;  
 import lejos.nxt.Sound;  
 import lejos.util.Delay;  
   
 public class BeamHoleCounter  
 {  
   private static final long BRICK_END_TIME_THRESHOLD_IN_MS = 200;  
   private static final int LIGHT_THRESHOLD = 550;  
   
   private final LightSensor sensor;  
   private final BeltDrive beltDrive;  
   private int brickCount = 0;  
   
   public BeamHoleCounter(LightSensor floodLight,LightSensor sensor, 
                             BeltDrive beltDrive)  
   {  
     this.sensor = sensor;  
     this.beltDrive = beltDrive;  
   
     floodLight.setFloodlight(true);  
     this.sensor.setFloodlight(false);  
     waitForFloodLightOn();  
   }  
   
   private void waitForFloodLightOn()  
   {  
     LCD.drawString("Waiting for", 3, 5);  
     LCD.drawString("Floodlight ON", 2, 6);  
     while(getLightValue() < LIGHT_THRESHOLD)  
     {  
       Delay.msDelay(5);  
     }  
     LCD.clear();  
   }  
   
   private int getLightValue()  
   {  
     return sensor.getNormalizedLightValue();  
   }  
   
   public void run()  
   {  
     beltDrive.forward();  
   
     int lightBeamBrokenCount = 0;  
     boolean stateAboveLightThreshold = true;  
   
     LCD.drawString("Light sensed: ", 0, 0);  
     LCD.drawString("Bricks: ", 0, 2);  
     LCD.drawString("Holes : ", 0, 3);  
     drawCounts(lightBeamBrokenCount);  
   
     long lastTimeLightBelowThreshold = System.currentTimeMillis();  
     while(true)  
     {  
       if(lastTimeLightBelowThreshold + BRICK_END_TIME_THRESHOLD_IN_MS 
            < System.currentTimeMillis() && lightBeamBrokenCount >= 1)  
       {  
         brickCount++;  
         int holesInBrick = lightBeamBrokenCount - 1;  
         drawCounts(holesInBrick);  
         lightBeamBrokenCount = 0;  
       }  
       int lightValue = getLightValue();  
       LCD.drawInt(lightValue, 3, 3, 1);  
   
       if(lightValue > LIGHT_THRESHOLD && !stateAboveLightThreshold)  
       {  
         stateAboveLightThreshold = true;  
         if(lightBeamBrokenCount != 1)  
           playLightBeamBrokenSound();  
       } else if(lightValue < LIGHT_THRESHOLD && stateAboveLightThreshold)  
       {  
         lightBeamBrokenCount++;  
         lastTimeLightBelowThreshold = System.currentTimeMillis();  
         stateAboveLightThreshold = false;  
       }  
     }  
   }  
   
   private void playLightBeamBrokenSound()  
   {  
     int volume = Sound.getVolume();  
     Sound.setVolume(50);  
     Sound.playTone(4000, 50, 100);  
     Sound.setVolume(volume);  
   }  
   
   private void drawCounts(int holesInBrick)  
   {  
     LCD.drawInt(brickCount, 2, 9, 2);  
     LCD.drawInt(holesInBrick, 2, 9, 3);  
   }  
 }  

Below is a slow-motion run where a beam passes through our sensors. Just below the camera is the floodLight and on the opposite side of the belt is the sensor. Look closely at the sensor while the brick is passing through. You should notice the light being broken and hear the sound from our program registering a hole.


Below is another run through our system where the NXT can be seen. Beams of length two and fifteen are going through our system. We could only find a black beam of length two, its pretty hard to see on the video, sorry. The display shows how many beams have passed and the length of the last one.

One key benefit with the design of the BeamCounter light sensor system, is that it is nearly independent on time. Time is only used for detecting if a brick has completely passed the sensors. If our conveyor belt speed changes, as could be the result of a depleting battery or because more friction was added to the system, our BeamCounter would still work as long as one beam hole would pass the light sensor faster than BRICK_END_TIME_THRESHOLD_IN_MS milliseconds. We believe we have built a very robust BeamCounter implementation.

6. Conclusion

We are very happy with the result so far. We have tested it with a lot of beams with different lengths, and so far the BeamCounter have been all correct. Beams are no longer getting stuck and small beams of length two can also be transported on the system and walls have been added to help guide beam past the light sensors.

7. Next lab

In the next lab we'll start working on the distributor car that should carry the car tray.

8. References

[1] “Embedded Systems, Embodied Agents - Lecture slides week 2.” [Online]. Available: http://legolab.cs.au.dk/DigitalControl.dir/NXT/Lectures/Lecture2/Lecture.pdf. [Accessed: 05-Jun-2013].