Aim
Design and build a set of calipers to measure the length of items, you will need to:
- Move to a fixed position - fully open.
- Slowly close the jaws, using an optical encoder to measure the distance travelled.
- Since the LEGO optical sensor is reflective, you will have to determine its focal length - the optimal distance to place the encoder - by experimentation (unless you find it documented somewhere).
- Stop when the object to be measured is engaged
- Display the calculated length of the item on the RCX's LCD panel.
Design Stages
The code development for this assignment was in two parts. First some skeleton code was produced that monitored the rotating disc and incremented a global counter on each segment change. Once this was shown to work and the physical robot had been built, code was built round this to control the directional movement of the jaws and to use the counter to perform measurments.
Disk Monitoring
Using a task based approach, we started with a simple counter task. This continually monitored the light sensor and incremented a global counter on every transition between segments.
Once the physical enclosure for the encoder disk and the light sensor had been built, we could see what kind of values appear were read by the light sensor for dark and light regions. It was noted that the light was around 57 and dark around 33. The central point between these two is 45, and this reading was decided to be used as a 'THRESHOLD' to mark between light and dark.
With the threshold ascertained, it was then a simple matter of keeping track of wether we are moving from light to dar, or from dark to light in a while loop and incrementing counters and changing direction as necessary, ala:
span class="co1">//Dir is true - we are going "up"
//Dir is false - we are going "down""
We were using the encoder disk with 16 segments, and to check the accuracy of the counter loop created a simple main function that beeped once per rotation. In experimentation we found it was acurate and didn't drift over time.
Object Collision Detection
Using the slip gear we made it so that the encoder disk stopped rotating when the object to be measured (or the end of the track) was reached. We could then detect this collision had happened by the stopping of the encoder disk transitions over a period of time. This meant we could implement our measuring system without needing the use of a switch to detect collisions.
This detection was done using one of the in-built system timers. On every transition we reset the timer, and if we detect the timer ever gets above a threshold ( 2 seconds we decided upon ) we change a variable to signal that the object has been encountered.
Searching and Resetting
Once the entire robot had been built, we put code around the counter task to control the motor and make the behaviours we wanted. We decided to have a 'Resetting' behaviour that would reset the jaws to the fully open position, and a 'Searching' behaviour that would search for the object from the fully open (reset) position.
It was decided that a push button would allow the user to reset the robot, and a second press would make it search. This was handled with a simple task that detects if the button has been pressed while we are not doing an action (button presses while a task is being performed are ignored to prevent accidental re-triggering).
span class="co1">//if button pressed and we arn't doing something already
Transitioning into the searching task also forces a reset of the count variable, so we can measure from 0 how far along the track we manage to go before encountering an object. We calibrated that the length of the track was 254mm, and that it took (on average) 123.67 counts to get from the start to the end (across a set of 6 readings). We used this to create a scaling factor of 2.1, so each click was equivalent to 2.1mm. Our theoretical-best accuracy was therefore ~0.2cm, which is 0.83% of the largest thing we could measure (which isn't too bad). We added code to perform the count-to-mm's conversion in the counter routine, and to display the result:
/* Recalculate value and display it */ value = LENGTH - (count * FACTOR); SetUserDisplay(value,1);