EG 120 Final Project


Development of a LEGO-Based Scale

Team #7
David Greene
Patrick Sullivan
Tia Likely

Nov. 7, 1995


Introduction

The purpose of this report is to familiarize the reader with the LEGO scale project, and to guide him or her through the development process.

The purpose of this project was to introduce freshman engineering students to key concepts that are essential to several fields of engineering. The scale project includes ideas from mechanical engineering, computer science, and physics (which is applicable to all fields of engineering). Also, the function of design teams was demonstrated.

In our development of the scale design, we considered several designs. The final design functions quite well, but improvements could be made.

Design Description

Our design uses a see-saw type device with a moving pivot to obtain the mass of an unknown object. It functions much like a physician's scale. The unknown mass is placed on one end of the see-saw, with a known mass at the other end.

With the physician's scale, the known mass is moved along the see-saw until balance is achieved. The idea here is that moving the known mass lengthens or shortens the distance from the pivot to the known mass. Basic physics tells us that an increased distance from the pivot provides increased torque. By changing this distance, one tries to make the torque on the known mass side equal to the torque on the unknown mass side.

The moving pivot scale described below uses the exact same concepts from physics. However, the distances are changed not by moving the masses, but by moving the pivot. The end result is the same, however.

A picture of our design is given below:

To operate the LEGO scale, one places the unknown mass in the right-hand pan of the balance (when looking at the scale). A known mass is selected and placed in the other pan. In this case, no known mass is used, as the mass of the left pan will act as the known mass. A control is set to tell the program how many measurements to make. On the computer terminal, the "Go" button is pressed. From here on, the scale is entirely computer controlled, with no intervention from the user required.

Several readouts on the computer screen provide useful information. Figure 1 below shows this screen.

The text area in the upper-left corner allows specification of the known counterbalance mass. This mass should be placed in the left pan. The "Go" button in the top-center was mentioned previously. The stop button tells the scale to halt all activity. This can be used if a disaster occurs.

The slider on the right allows the user to specify how many independent measurements to make. The more measurements made, the more accurate the reported mass and errors will be.The large text area in the middle-right is used to display any error messages. These can be things like an empty Known_Mass field, or a mass that cannot be determined (if the see-saw tilts to the left initially, indicating that the known mass is too heavy).

The bottom row of fields displays the mass as well as two error estimates. The first is derived from an error propagation formula based on a level arm distance error of .2 cm. This is the worst error we observed. The Standard_Deviation field shows the standard deviation of the independent mass determinations. In the case shown above, a 5.6699 gram mass was massed with the scale. The reported mass is 6.2245 grams, which gives an error of .5546 grams. In this case, the error propagation formula presented the most accurate result. The two error displays are a nice extra feature that provides a little more information to the user.

Our user interface includes a diagnostics page. This is another extra feature of the design that was added as the scale developed. The page, shown below, contains a Log display which is written to by the program. This will show any debugging statements added to the program. There are also several status displays, including an English readout of the last tile measured, a count of the number of iterations, and a graph showing how the tilt changed with each iteration.

We decided to add the diagnostics page almost immediately in the design process. The information it provided was extremely useful in correcting our algorithm, especially toward the end, when several subtle bugs caused strange errors.

Overall, the scale functions well. Most masses can be determined to within 5 grams, as stated in the problem requirements. However, as mentioned above, the accuracy of the scale decreases as the mass increases. This is most likely due to the increased friction forces caused by the heavier m asses, which would affect the ability of the see-saw to swing freely. Error estimates are generally within 3 grams, with the worst case observed being 6 grams (on a mass of 17 grams). We believe that if time permitted, we could improve on this performance.

Technical Overview

As mentioned in the previous section, our scale design uses a crucial concept from basic physics: the lever-arm. In the diagram below, two masses are on a see-saw, which is perfectly balanced:

The equation governing this action is

M1L1 = M2L2

This can be derived with the following method:

The torque provided by either mass is determined by this relationship:

t = FL

Where F is the force on the point of action, and L is the distance from this point to the pivot. Now, sinceF = Mawhere a is the acceleration of gravity (9.8 m/s2),

t = MaL

In equilibrium (balance), all torques must sum to zero:

Sum(t) = 0

So we set the two torques equal to each other and rearrange:

MaL1 = MaL2 => M1L1 = M2L2

We thus arrive at the desired equation.

When thinking about how to design a scale, several ideas quite different from the moving pivot were discussed. The first idea was a simple pan balance where the unknown mass would sit in one pan while known masses were loaded into the other. However, because of the restriction that only one counterbalance could be placed on the scale before it was started, some sort of robotic arm or conveyor system would be needed to load additional known masses. We deemed this to be a project that would overrun the available time to complete the project, and thus it was not attempted.

Another idea we had was to create a hanging spring balance. The unknown mass would hang from a spring, and a light sensor would move vertically until it could see a light attached to the bottom of the mass. The distance the sensor moves from its original position is a linear function of the masses measured and the spring constant. This is a design that uses a very simple concept. We actually tried developing this scale in parallel with the moving pivot scale, but we encountered a few problems.

Our spring scale design had difficulties getting off the ground because of material problems. We initially wanted to implement two distinct working versions of scales that both had different advantages and disadvantages. Unfortunately, the spring scale was not completed.

In attempting to design a scale that measured a mass based upon the distance it caused a hanging spring to move, we ran into various difficulties. One major problem we had was finding a spring that could actually move any major, measurable distance. We went on various shopping excursions, all attempting to find a somewhat flexible spring to be used in our implementation of a scale. But, we failed to find a sufficiently flexible spring and determined to devote more time on our other project, the moving pivot scale.

Another problem with the spring scale was finding a way to adequately attach it to the Legos so that it would not just pull them apart. The problems were that Legos simply could not hold on to the springs we used adequately enough. They would separate apart, possibly due to the fact that the springs we used were not flexible enough, as detailed.

We also had trouble with getting enough Legos to implement both of our designs. Given the limited Legos available, we would be hard pressed to create both designs as accurately as they would need to be. After implementing the mobile pivot scale, we lacked the motor needed to move the light sensor to measure the distance x. We would have needed to create a larger frame than we had Legos for.

The fact that this method only required two measurements, that of k, the spring constant; and that of x, distance moved, really made the failure of this method all the more disappointing. It would have been an implementation that would, once completed, be almost independent of human error. The operator could not cause a wild result; the result would occur exactly as it was programmed to occur.

Work done on this part of the experiment before the realization that an adequate spring would not be found included an attempt to build a structured frame to hold the spring up as well as some kind of pan to rest the unknown weight in. We also attempted to create a mobile light sensor using the tracking pieces we used in the pivot scale. All of these had associated difficulties that were not resolved because a spring that would work as we desired was never found. The work put into this project makes it all the more disappointing that our biggest limitation was that of material. Given adequate equipment, we would have been able to construct a working scale.

When we realized a spring could not be found, we had a spark of imagination and thought of using a rubber band. We had little time left to attempt to develop a design of this style and we felt that our mobile pivot scale worked well. We also lacked the necessary Legos to try a new design.

The final idea we had was to create a scale that does not require gravity to function. If a mass is attached to the spring, the spring is stretched (or compressed) some distance and then released, the mass will exhibit simple harmonic motion, with the period of motion determined by the mass of the object. The biggest problem we saw with this design was keeping the motion of the mass in one plane without introducing extra friction forces. Again, we never tried to build this scale, and the lack of a suitable spring would certainly have hindered us here also.

We chose the moving pivot design over these other designs because we knew it could be built using only the given LEGO blocks. Introducing outside parts like springs creates new problems, such as how to interface these parts to the LEGO blocks. We also thought that the moving pivot design was the most interesting. It covers gearing concepts from mechanical engineering, which we were all interested in. In addition, we believed the programming required with this project would be somewhat more extensive than with the other projects, as the scale would have to react and change based on feedback from the sensors, while the other scale programs would be more ÒstaticÓ in that they would only be measuring devices. We all have very good programming skills, so we did not see this extra work as a major problem.

The "guts" of the controlling program (included at the end of this report) are the balance and check.balance procedures. The program uses a simple algorithm to achieve the desired results. The pivot starts out in its left-most position. If the scale is tilting to the left, there is nothing that can be done, and the program exits. If it tilts to the right, the pivot is moved half way down the see-saw. If the see-saw is still tilting right, the pivot is moved again, half way to the right-most pivot position. As long as the see-saw tilts to the right, the pivot is moved in this manner. As soon as the tilt is to the left, the pivot is moved half the distance back to its previous position. Thus, on the average, the distance to the correct pivot position is halved with every move.

The initial goals set for the project are outlined in the team timeline that was developed.

Development Process

The theoretical model for the design is very straightforward. However, implementing it in LEGO blocks is another matter. The first problem was to figure out how to move a pivot and balance a see-saw on it. The immediate idea was to use one of the LEGO axle pieces as the pivot. However, we soon discovered that the see-saw would slide right off the pivot when it wasnÕt balanced. We then had the idea of using a small gear as the pivot, and placing the Òtooth-trackÓ type Lego pieces on the bottom of the see-saw. This solution works very well, allowing the see-saw to swing freely while still holding it to the pivot. It was one of the key inventions the team came up with.

The next step was to get the pivot moving. Our final solution uses a single electric motor attached to a gear box that reduces the rotational speed of the pivot. An axle protrudes from the gear box, and a gear at the end of this axle moves along the Òtooth-trackÓ type LEGO pieces placed along the route of the motor. A second axle/gear combination provides a reverse motion for the pivot, so that the motion gear and pivot gear are not moving along their respective tracks in opposite directions, which would cause unfortunate stresses that would likely tear the scale apart. The rotation of the pivot axle is measured with an angle sensor. Exactly 50 rotations of the sensor mechanism are needed to move the pivot from its left-most position to its right-most position.

These were the two major obstacles to be overcome. Several more problems presented themselves through the design process. The first was keeping the see-saw on the pivot while it was being moved. Originally, we had hoped to use a robotic arm to hold the see-saw steady. The next idea used a robotic arm to actually lift the see-saw off the pivot while it was moved. Both proved very difficult to do, and were quickly abandoned.

The final solution uses two stabilizers which look remarkably like ducks. These "ducks" are positioned at either end of the see-saw and can move toward or away from the pivot. They have sloping protrusions which are able to lift a tilted see-saw into a more balanced state which they are moved in toward the pivot. This provides enough stability so that the see-saw does not fall off the pivot when the pivot is moved.

Another problem we encountered was accurately measuring the distance the pivot moves. The original angle sensor we used gave 50 rotations for a pivot movement of about 8.5 cm. However, this gives an accuracy of only .17 cm per rotation. Any movement less than .17 cm was impossible. To improve this situation, we used another angle sensor to measure the rotations of the motor directly. Unfortunately, when moving long distances, this sensor could not keep up with the quick motor rotations, and was useless. However, we eventually used both sensors. The first was used to get a rough idea of the correct pivot position. As soon as the desired distance to move is less that .17 cm, the program switches to the second sensor. Because the pivot is moving a very small distance, this sensor can now accurately measure the motor rotations. This sensor is used to fine-tune the rough approximation given by the first sensor.

Work was partitioned among teams members in a somewhat random manner. Specific goals were outlined in a team time-line, and members were allowed to choose which projects they wanted to work on. We hoped this would allow team members to get experience in a wide variety of areas. Also, we thought it was important that all members knew how the various parts of the design worked and fit together.

When designing the scale we found that the sub-tasks that were identified were just about right. They were not too complex, but they were large enough so that we did not get bogged down in details.

Performance Assessment

The economic analysis of the design produced these results:

		3 motors @ 100 points	
	+	4 sensors @ 50 points	
	+	9 gears @ 30 points	
	+	1 lamp @ 25 points	
	+	1 wire @ 20 points	
	+	4 axles @ 10 points 	
	+	0 extra parts @ 5 points	
	=	855 points

Mass producing this design should not be too difficult. The most important consideration is the meshing of the pivot gear with the "tooth-track" type pieces. If this does not mesh cleanly, the pivot will not move along the scale bar correctly.

Manufacturing the gear box could prove to be somewhat expensive, due to the large number of axles and gears. Also, the track that the pivot motor moves along will have to be polished very well in order to reduce friction forces.

The engineering performance of the scale produced these results:

As mentioned above, we solved the see-saw/pivot moving problem with the "ducks." Unfortunately, this required the use of two extra motors, which really increases the cost. One motor could be eliminated if gearing to control both "ducks" from one motor was developed. This would prevent independent operation of the "ducks," and the control algorithm would have to be modified. Also, the vibration caused by moving both "ducks" simultaneously might cause problems.

One consistent problem with the design occurs on a reset. When the motor/gear mechanism hits the touch sensor, it begins to lift off the track and turn to the left, which also causes the see-saw to turn to the left. When the pivot begins moving, the thin wheel on the end of the pivot that helps to hold the see-saw in place rubs against the see-saw. Sometimes, the motor cannot overcome this force. This reveals another problem: when the pivot is moved, the "ducks" must keep a constant force against the see-saw. This requires that all three motors be operated simultaneously. This seems to put an enormous strain on the power output capabilities of the control box, and decreased motor performance is definitely noticeable.


Scale Procedures

to main   
   reset	   
   make "duck 0   
   make "tilt_list []   
   make "direction 1   
   make "distance 10.1   
   make "count 1   
   make "mass_list []   
   control.duck   
   check.balance   
   make "lastcode :code   
   make "tilt_list []   
   if not :halt = 1 [      
      ifelse :code = 0 [         
         talkto "Errors         
         cleartext         
         print [cannot measure this mass]      
      ]      
      [         
         repeat :measurements [            
            inner.loop             
            calculate.mass            
            talkto "motora off	      
            talkto "motorb off		
            talkto "motorc off            
            make "mass_list insertitem :count :mass_list :mass            
            make "count :count + 1            
            reset         
         ]      
      ]      
      talkto "Mass      
      cleartext      
      print average :mass_list      
      calculate.error   
   ]
end

to inner.loop   
   loop [      
      ifelse not :code = 2 [         
         balance         
         talkto "|Cycle Count|         
         cleartext         
         print :cycle_count      
      ]      
      [         
         stop      
      ]   
   ]
end

to reset   
   talkto "Log cleartext   
   talkto "Errors cleartext   
   talkto "Mass cleartext   
   talkto "Error cleartext   
   talkto "Standard_Deviation cleartext   
   make "duck 0   
   make "direction 0   
   make "distance 10.1   
   make "coarse_distance_per_rotation .1603   
   make "fine_distance_per_rotation .0202811   
   make "distance_per_rotation :coarse_distance_per_rotation   
   make "cycle_count 0   
   make "halt 0   
   make "code 1   
   make "pan_mass 17.0097   
   make "distance_error .2   
   talkto "lampd on   talkto "motora setpower 8   
   talkto "motorc setpower 8   
   talkto "motorb setpower 5   
   talkto "motora setright onfor 4   
   talkto "motorc setleft onfor 3   
   talkto "lampd on   
   talkto "motorb setleft   
   talkto "motorb on   
   waituntil [touch1] talkto "motorb off   
   resetrotation 5   
   make "known_mass Known_mass   
   talkto "Log print [Known mass is]   
   print :known_mass   
   if or empty? :known_mass not number? :known_mass [      
      talkto "Log      
      print [No mass specified]      
      talkto "Errors      
      print [Please specify a known mass]      
      make "halt 1   
   ]   
   make "measurements slider1   
   talkto "Log print [Number of measurements to be made:]   
   print :measurements
end

to control.duck   
   ifelse :duck = 0 [      
      ifelse :direction = 0 [         
         talkto "motora setright onfor 2      
      ]      
      [         
         talkto "motora setleft onfor 2      
      ]   
   ]   
   [      
      ifelse :direction = 0 [         
         talkto "motorc setleft onfor 4      
      ]      
      [         
         talkto "motorc setright onfor 4      
      ]   
   ]
end

to balance   
   check.balance   
   if and (:code = 2) (:distance >= :coarse_distance_per_rotation) [      
      make "coarse_angle angle5   
   ]   
   talkto "Log   
   print [Tilt is ] print :code   
   print [Last tilt was ] print :lastcode   
   if and (:distance / 2) < :distance_per_rotation :distance_per_rotation <> :fine_distance_per_rotation [      
      resetrotation 7      
      make "distance_per_rotation :fine_distance_per_rotation      
      talkto "Log      
      make "coarse_angle angle5      
      print [Switching to fine adjustment]   
   ]   
   if not :code = 2 [      
      ifelse and :code = 0 :lastcode = 0 [         
         make "direction 0         
         make "distance :distance / 2         
         control.pivot      
      ]       
      [         
         ifelse and :code = 0 :lastcode = 1 [            
            make "direction 0           
            make "distance :distance / 2            
            control.pivot         
         ]         
         [            
            ifelse and :code = 1 :lastcode = 0 [               
               make "direction 1               
               make "distance :distance / 2               
               control.pivot            
            ]            
            [               
               make "direction 1               
               make "distance :distance / 2               
               control.pivot            
            ]         
         ]      
      ]    
   ]   
   make "lastcode :code
end

to check.balance   
   make "duck 0   
   make "direction 1   
   control.duck   
   repeat 500000 []   
   ifelse and light6 >= 45 light6 < 60 [      
      talkto "Tilt cleartext      
      print [left tilt]      
      make "code 0   
   ]   
   [      
      ifelse light6 >= 70 [         
         talkto "Tilt cleartext         
         print [right tilt]         
         make "code 1      
      ]      
      [         
         talkto "Tilt cleartext         
         print [balanced]         
         make "code 2      
      ]   
   ]   
   make "direction 0   
   control.duck   
   repeat 500000 []   
   make "direction 1   
   make "duck 1   
   control.duck   
   repeat 500000 []   
   make "duck 1   
   make "direction 1   
   control.duck   
   make "tempcode :code   
   ifelse and light6 >= 50 light6 < 60 [      
      talkto "Tilt cleartext      
      print [left tilt]      
      make "code 0   
   ]   
   [      
      ifelse light6 >= 70 [         
         talkto "Tilt cleartext         
         print [right tilt]         
         make "code 1      
      ]      
      [         
         if not :tempcode = 0 [            
            talkto "Tilt cleartext            
            print [balanced]            
            make "code 2         
         ]      
      ]   
   ]   
   make "direction 0   
   control.duck   
   if or (and :code = 0 :tempcode = 1) (and :code = 1 :tempcode = 0) [      
      talkto "Tilt cleartext      
      print [balanced]      
      make "code 2   
   ]   
   if and :distance = 0 :cycle_count >= 40 [      
      if not :code = :lastcode [         
         make "code 2         
         talkto "Tilt cleartext         
         print [balanced]      
      ]   
   ]   
   ifelse :code = 2 [      
      make "tilt_list insertitem :cycle_count + 1 :tilt_list 0   
   ]   
   [      
      ifelse :code = 1 [         
         make "tilt_list insertitem :cycle_count + 1 :tilt_list 1      
      ]      
      [         
         make "tilt_list insertitem :cycle_count + 1 :tilt_list -1      
      ]   
   ]   
   setdata 1 :tilt_list   
   make "cycle_count :cycle_count + 1
end

to control.pivot   
   talkto "motorb setpower 4   
   talkto "motora setright on   
   talkto "motorc setleft on   
   make "tempangle angle5   
   ifelse :distance_per_rotation <> :fine_distance_per_rotation [      
      ifelse :direction = 0 [         
         talkto "Log         
         print [Moving pivot left] print :distance         
         talkto "motorb setleft on         
         waituntil [((abs :tempangle) * :distance_per_rotation - (abs angle5) * :distance_per_rotation) >= :distance]         
         talkto "motorb off      
      ]      
      [         
         talkto "Log         
         print [Moving pivot right] print :distance         
         talkto "motorb setright on         
         waituntil [((abs angle5) * :distance_per_rotation - (abs :tempangle) * :distance_per_rotation) >= :distance]         
         talkto "motorb off      
      ]   
   ]   
   [      
      make "tempangle angle7      
      ifelse :direction = 0 [         
         talkto "Log         
         print [Moving pivot left] print :distance         
         talkto "motorb setleft on         
         waituntil [(abs ((abs :tempangle) * :distance_per_rotation - (abs angle7) * :distance_per_rotation)) >= :distance]         
         talkto "motorb off      
      ]      
      [         
         talkto "Log         
         print [Moving pivot right] print :distance         
         talkto "motorb setright on	   
         waituntil [(abs ((abs angle7) * :distance_per_rotation - (abs :tempangle) * :distance_per_rotation)) >= :distance]         
         talkto "motorb off      
      ]   
   ]   
   talkto "motora off   
   talkto "motorc off
end

to calculate.mass   
   make "larm :coarse_angle * :coarse_distance_per_rotation + 3.15   
   if :distance_per_rotation = :fine_distance_per_rotation [      
      make "larm :larm + angle7 * :fine_distance_per_rotation   
   ]   
   talkto "Log   
   print [Final left lever arm is: ]   
   print :larm   
   make "rarm 14.35 - :larm   
   print [Final right lever arm is: ]   
   print :rarm   
   make "mass (:known_mass + :pan_mass) * :larm / :rarm - :pan_mass
end

to calculate.error   
   make "devs []   
   make "index 1   
   repeat :measurements [      
      make "devs insertitem :index :devs (((item :index :mass_list) - (average :mass_list)) * ((item :index :mass_list) - (average :mass_list)))      
      make "index :index + 1   
   ]   
   make "error sqrt ((average :devs) * :measurements) / sqrt (:measurements - 1)   
   talkto "Standard_Deviation   
   cleartext   
   print :error   
   make "error_prop (:pan_mass / :rarm) * (:pan_mass / :rarm) * (:distance_error * :distance_error)   
   make "error_prop :error_prop + ((-1 * :pan_mass * :larm) / (:larm * :larm)) * ((-1 * :pan_mass * :larm) / (:larm * :larm)) * (:distance_error * :distance_error)   
   make "error_prop sqrt (:error_prop)   
   talkto "Error   
   print :error_prop
end