The goal of this project was to develop a working electronic device for the "robot art show" at the end of the year. (This was just a name for the informal presentation style — the constructed device did not have to be related to art or artwork.) The design process encompassed the wide variety of skills and concepts related to electronics, programming, and robotics in general. Because of this, we studied many of these subjects in class, including:
Static electricity
Power generation (Turbines)
Electromagnetism (Motors)
Circuit principles — Ohm's law, Kirchoff's laws, series, parallel, etc
Programming and the Arduino framework
The project started to materialize once we got into circuits and programming. First, we made some basic series and parallel circuits with resistors and batteries. We used multimeters to verify Ohm's law (see the Core Concepts section) on these circuits and then began to make more complex circuits with light bulbs, LEDs, potentiometers and later capacitors, IC chips, and more. This culminated in the "Blinky Light Quiz" where we were tasked with blinking a light using a 555 timer chip. After this, we moved our focus to using Arduino boards to create more complex behavior. We used the Arduino C++ environment to create programs for a variety of experiments, including a digital piano, a memory game, and a guessing game. At this point, the class was ready to start working on the robot art show itself.
The only constraint on the project's design was that you challenge yourself — as I had worked with Arduino and electronics many times before, and as my teammate was fairly experienced with programming, we were ambitious in planning our project and decided on creating a physical replica of the 1979 game "Lunar Lander". We went through a few design iterations before settling on our final plan, which we then constructed faithfully. (The completed machine can be seen at right.) The game starts by displaying a series of instructions on the LCD screen near the joystick. Then, the main gameplay initializes — the LCD readout changes to fuel remaining and current speed, and the lander begins its descent to the lunar surface. This is facilitated by the two servos, which allow the machine to vary the length of the string between the servo and the lander mechanism via two pulleys. Through some simple algebra, the Arduino can precisely move the lander to any given point in the X-Z plane simply by rotating these servos.
In addition, the lander mechanism has an additional servo which gives the lander rotational freedom, allowing the user to rotate the lander in order to change the angle of thrust. This input is provided by the joystick, which controls thrust (up) and rotation (left-right). Internally, this is then processed and accurate laws of physics are used to calculate the movement of the lander in "space". The goal of the game is to safely land the lander on the paper-mache lunar surface, and if this is achieved the player receives a celebration message on the LCD screen. If not — if they went too fast, or if the lander fell over on impact — then a failure message is shown. A video of the game running can be seen below.
Some of these concepts were not directly used in the final project, however they were studied in class and thus they will be included here.
When electricity isn't moving, it's called "static electricity". This is the kind of electricity that gives you a little shock when you touch metal after riding a plastic slide or makes your hair puff out when you rub a balloon. The way to conceptualize static electricity is a world full of point-like "charges" which have a value (either positive or negative). In reality, these charges are actually the electrons in atoms, but due to a historical mishap a "positive" charge is actually a lack of electrons while a "negative" charge is a surplus of them. The way these charges interact is where things get interesting. In the simplest case, imagine we have two charges sitting near each other. How will they end up moving relative to each other? There is a simple rule for this:
Like charges repel, and
Opposite charges attract
So, if we have a positive charge and a negative one, they will be attracted together, while two positive charges or two negative charges will move away from each other. As we add more charges into the model, we end up with more and more attractions and repulsions which add together to create the overall effect on each particle. Now, the issue with the above rule is that it leaves out a critical detail: how much will they get attracted or repelled? This factor is accounted for in Coulomb's Law, which states that
F = k(q₁ • q₂) / r²
where F is the force (in Newtons) between charges q₁ and q₂, r is the distance between them and k is the Coulomb constant (around 8.99 • 109 kg • m3 • s−2 • C−2). The charges qᵢ are measured in Coulombs, a unit of charge denoted "C". This may look familiar — indeed, it is algebraically homogenous to Newton's law of universal gravitation (differing only by a constant factor). This is because the attraction between charges follows the inverse square law, just like gravity, and this form represents such a relationship. With this information, it is possible to determine how charges will move based on the charges around them.
Keeping this in mind, it is now possible to consider why you can see the effects of static electricity. By its nature, rubber has a large amount of negative charge (a large number of electrons). Conversely, human hair has a large positive charge (a small number of electrons). Therefore, when you rub your hair on a balloon, these two charges should want to pull together (remembering that like charges attract) — but it's actually even stronger than that. Instead, the charges not only pull each other together but they actually jump between the materials. Because rubber has more electrons already, the attracted electrons in your hair jump over to the rubber, giving the rubber an even larger negative charge and your hair and even larger positive charge. This is called the triboelectric effect. (A table called the "triboelectric series", depicting which materials give off electrons and which gain them, is shown at right.) And now, this is why your hair starts to puff out: like charges repel, and since your hair now has much more positive charge distributed all throughout it, each strand tries to repel the others and as a result they all stick out.
A circuit is simply a conductive loop. Conductive meaning that electrons are able to move along this path, and loop meaning connected to itself in some way (thus a figure-8 or other more complicated multi-loop paths are still circuits). To begin, let's imagine a very simple circuit: a circular loop of conductive wire. This circuit is not very interesting: all the electrons in the wire are simply sitting still. In order to make it more interesting, we have to add two elements: a voltage source and a current source.
Current is the amount of "flow" in a circuit — this is how "fast" the electrons are moving through the wire. If we imagine the circuit is a water pipe instead of a wire, this would be how fast the water is flowing. Voltage, on the other hand, is the "amount" of electrons moving in the circuit. In the water analogy, this is like the pressure of the water (higher pressure means more water in the same amount of space moving down the pipe). Luckily, we do not have to add these things independently into a circuit: both can be added at once by using a standard battery, which provides a fixed voltage (such as 1.5V for a AA or 9V for a 9V battery) and some amount of current. (The exact workings of how it does so is beyond the scope of this discussion, but in essence it is a chemical reaction which moves the electrons. This chemical reaction only lasts for a certain amount of time, which is why batteries don't run forever.) You might expect it to provide a fixed current, but this is not the case. Returning to the water analogy, a battery is like a pump. Obviously, if you connect tiny pipes to the pump and then ask the pump to move a huge water pressure (large voltage) through that pipe, it will not be able to move the water very fast (low current)! Conversely, if you ask it to pump that same water pressure (same battery voltage) through a very large pipe, it will do it with ease and result in a fast flow (large current). Here we see an interesting relationship: with a fixed voltage, current through a circuit will vary depending on the resistance throughout the rest of the circuit. This is more generally formulated in the form of Ohm's Law, one of the fundamental principles of circuit analysis:
V = IR
where V = voltage measured in Volts, I = current measured in Amperes (recall that Coulombs is C, thus current cannot be letter C) and R = resistance measured in Ohms. Looking at our previous example, if we hold V fixed we see that a larger R results in a lower I while a smaller R results in a higher I. Therefore, Ohm's law holds up intuitively, and it can indeed be verified with a few simple experiments.
Now, what provides the resistance? Well, in the case of our loop, there is none. So, if we add a battery into that loop (essentially, connecting the positive battery terminal to the negative one with nothing in between) our equation from Ohm's law becomes V = I • 0. Assuming the battery is not dead (0V), this would require the current to be infinitely high! Of course, in reality a wire cannot have zero resistance since the metal itself provides a small resisting force, but this resistance is so negligible that the current is still astronomically high. It is this exact phenomenon that is known as a short circuit — if you try this yourself, you will see that the battery quickly runs out of power when such an arrangement is held for any extended amount of time. This is because the battery is having to provide huge amounts of current which will soon use up all its energy. (Think of the energy used by a small pump attempting to move water at the speed of sound.) One important point is brought up by this thought experiment however: it is clear that there is some measure of the battery's total "energy" which should take into account both voltage and current. This measure is called Power, and it is measured in Watts (W) which is equivalent to Volts • Amperes (V • I).
If we don't want to continue pouring our money into wasted batteries, we need to add resistance to this circuit. Luckily, there are electronic components designed exactly for this purpose: resistors! Each resistor has a given resistance value, in Ohms, so by selecting a resistor and instead placing this resistor into the loop with the battery it is simple to see that the current will be much lower. (For instance, a 1 kilo-ohm resistor placed in a loop with a 1.5V battery will result in a current of 0.0015 Amperes, or 1.5 milliamps — a very reasonable current.) Of course, resistors by themselves don't actually do anything useful, so we can also add a light bulb or an LED (a semiconductor which generates light) into the circuit as well. Light bulbs have moderate resistance by themselves, so it would likely be safe to simply put the lightbulb alone with the battery (without a resistor). But, LEDs have almost no resistance inside, so when using an LED we must also put a resistor into the circuit. The question is... now that we have three components, how do we arrange them? There are two meaningful ways to arrange these three components: putting the LED and resistor in series or in parallel. A depiction of each is shown below (green indicates a positive voltage, and the lines are wires).
Series
Parallel
To decide which to use, we need to know how current and voltage are affected by these different layouts. (Obviously, we want the current through the LED to be the same as that through the resistor — otherwise, we end up with the same V = I • 0 issue, since the LED has effectively no resistance.) We need a new set of laws to define this, but first let's tackle this problem intuitively. We'll start with series.
Let's use the water model to imagine the series circuit. Water from the pump goes first to the LED, a nice wide pipe with little resistance, and then to the resistor, narrowing down to a thin pipe with high resistance, before returning back to the pump. What will be the current through each component? Well, even though the LED's pipe is wide, the water can't go fast since immediately after it must go slowly through the resistor's pipe. It's like having to slow down on a wide road because the road narrows later on — even though you could normally go fast, you can't because of what's ahead. Therefore, we see that in a series circuit, current is the same through all components. Now, what about voltage? Well, let's defer to algebra for a moment: since we know the resistance of the components, and we now know the current through the entire series circuit, we see that V = IR means in a series circuit, voltage is proportional to the resistance of the component. (Think about it: we have a fixed I in all the components, so we can ignore that if we say "proportional", and that just leaves "voltage is proportional to resistance".) Returning to intuition, it is clear that in the thin high-resistance pipe the water must be "packed tighter" than in the wide low-resistance pipe — thus there is higher pressure in the high-resistance pipe meaning it has a higher voltage.
Now, let's look at parallel. This one is a little trickier — let's start with voltage. How does the pressure change at the split? Well, it doesn't: there's simply two pipes now, but still with the same pressure. (Consider this one for a moment, as it is a bit less immediate than the previous conclusions.) So, in a parallel circuit, voltage is the same through all pathways. Hmm... this sounds familiar! Recall that in a series circuit, this is exactly how current behaves for each component. Perhaps, then, current will split proportional to the resistance of each pathway, just as voltage did before for each component. To verify this, let us once again turn to Ohm's law. We now know the voltage through each pathway is the same, so we can see that I = V / R (a quick rearrangement of the original law) means that in a parallel circuit, current splits inversely proportionally to the resistance of each pathway. (Our V is constant, so we have "I is proportional to 1 / R".) Intuitively, this makes sense: if the water is faced with two possible paths, one with low resistance and one with high resistance, most of the water will go down the low-resistance route and only a small amount will travel down the high-resistance route.
So there we have it — four rules that define how voltage and current behave in series and parallel. These laws are a somewhat alternative formulation of Kirchoff's Laws (they have been presented this way in the interest of explicitness). All that is left is to resolve the original question: should we choose parallel or series to make sure the LED has the same amount of current flowing through it as the resistor? Well, looking at our laws, we see that current is the same through all components in a series circuit — thus we know to put the resistor and LED in series in order to make sure too much current does not go through the LED. (If we were to choose a parallel circuit, the current would split inversely proportionally to the resistance of the LED and the resistor; thus almost all the current would go through the LED, as its resistance is quite low, making the current astronomically high once again.) Through a little algebra, we can also solve for resistance instead of current/voltage given these laws to simplify our conclusion: in a series circuit, the total resistance is the sum of the resistances of each component, and in a parallel circuit, the inverse of the total resistance is the sum of the inverses of the resistances of each component. (The second one is slightly harder to understand in words — it means that 1/[total resistance] = 1/[resistance of component 1] + 1/[resistance of component 2] + ...)
Of course, these two arrangements are only the start of limitless other possible combinations when you begin adding more components. Complex circuits can be made from many compound constructions of both parallel and series circuits together in order to create complex behavior. However, these same rules always apply, which allows you to analyse any circuit to produce the desired effect. Likewise, there are many other electronic components which can provide different functions (such a switches, which can stop current, capacitors, which can store charge, and transistors, which act like controllable "valves"), but the rules of voltage, current and resistance always apply to any component. (Unless it is a superconductor — then the previous argument that all components have resistance is false.)
By creating very complex circuits (very cannot be stressed enough), it is possible to construct devices which can perform multiple functions. For instance, imagine we have created a much simpler device which can do one of two things: turn on a light or beep a buzzer. Let us also imagine that the way to select which function it performs is to set a switch on the device to one of two positions. Now, let's suppose we have a specific purpose for our general-purpose-blinky-beeper™ in mind (a purpose which is, of course, turning on a light or beeping a buzzer). How would we tell the device how to do this purpose? In this case, it is trivial: simply set the switch to the desired function. This act of "telling the device what to do" is called programming.
Of course, our imaginary device is not very useful. So let's make a new device which can do one of three things:
Turn on the light
Turn off the light
Check if a button on it is pressed, and if it is, skip the next command
At this point, the device is getting a bit more complex. And as hinted by the third command, it's going to need a modification: being able to execute multiple of these "commands", one at a time. So how do we program it now? Well, we can write down a "to-do list" for the machine and (supposing we have some kind of input parser for it) give the list to the machine to have it run. This form of programming is much more similar to what we use in the modern day — though of course, we do not use physical to-do lists (a.k.a punchcards) anymore, but we instead transfer the data to the machine via digital inputs. Returning to our imaginary machine, let's examine a possible to-do list for it:
Turn on the light
Check if a button is pressed, and if it is, skip the next command
Turn off the light
So, we have two possibilities here. Suppose we have the machine run the to-do list when we are not pushing the button. Then, it will a) turn on the light, b) check if the button is pressed — which it is not, so the next command is not skipped, and finally c) turn off the light. Thus, the machine will just quickly blink the light (or if the commands are run fast enough, you will not even see the light turn on in the first place). What if the button is held down? In that case, it will a) turn on the light, b) check if the button is pressed — which it is, so the next command is skipped and there is nothing left to do. So, if we do hold down the button then the light will remain on. This illustrates a primitive form of decision making: our machine is able to decide what to do based on whether the button is pressed. We've successfully made a button trigger a light. How exciting.
Thankfully, more complicated devices allow more complicated programs that are not as... underwhelming. One example of such a device is the Arduino microcontroller (see right). Instead of just turning on a light, this device can turn on any devices connected to each of its 13 output pins (wire connectors). Therefore, an Arduino can blink a light, beep a buzzer, move a motor, and draw an image on a screen — all at the same time! Additionally, it can also read input values from these pins (as well as 5 other pins which can read analog variable-voltage values instead of just "on" or "off"), allowing it to make decisions based on inputs from the outside world.
But, with great power comes great responsibility. To be able to construct more complicated programs ("to-do lists") for this device, a much more powerful programming language is required. A programming language is simply a format for your to-do list — for instance, instead of writing down "turn on the light", the programming language might dictate that you write down ROBOT, PLEASE TURN ON THE LIGHT. In this case, you must write ROBOT, PLEASE TURN ON THE LIGHT and nothing else in order for the device to understand it; so ROBOT, TURN ON THE LIGHT NOW won't work!
The programming language used by the Arduino platform is a variation on the C++ language. As a quick introduction to the various concepts in the language:
You define a series of "functions" in the program. A "function" is like a routine — when you tell the Arduino to execute the function, it will run exactly what you define the function to be. So if you write (in pseudo-code):
function GET_ME_WATER:
OPEN_FRIDGE()
TAKE_WATER()
GIVE_WATER_TO_ME()
end
...where () after a name means "execute this function", running GET_ME_WATER() will run OPEN_FRIDGE(), then TAKE_WATER(), and then GIVE_WATER_TO_ME().
Many times, a function is just a routine — something you do. However, in other cases a function returns a value. This means that calling a function will compute some value and then give it back to you. An example (in pseudo-code):
function CALCULATE_PI_FOR_ENGINEERS:
return CALCULATE_EULER()
end
So, when you call CALCULATE_PI_FOR_ENGINEERS() the machine will return the value computed by CALCULATE_EULER().
Sometimes, you might want to give a value to a function too. For instance, if you want to make a function to add two numbers together and then multiply that by two, you could write (in pseudo-code):
function ADD_THEN_DOUBLE (x, y):
return (x + y) * 2
end
... where the (x, y) means "This function takes in two arguments (values) — call the first one x, and the second one y". So running ADD_THEN_DOUBLE(1, 2) will call 1 "x" and call 2 "y", then compute (x + y) * 2 = (1 + 2) * 2 = 3 * 2 = 6, which it will return (6).
You can make new names, called "variables", for things as well. This can make things more readable. For instance, you could write:
function THIS_USES_VARIABLES:
x = 3.14
y = 9.0
x = x - 0.14
return ARE_THESE_EQUAL(x * x, y)
end
Calling THIS_USES_VARIABLES() would first assign 3.14 to x, then 9 to y, then would assign x - 0.14 = 3.14 - 0.14 = 3.0 to x (so x is now 3 and y is still 9), and finally return the result of ARE_THESE_EQUAL(x * x, y) (which is the same as ARE_THESE_EQUAL(3 * 3, 9)).
In the real Arduino language, each name has a type which tells the computer what kind of value it stores. Moving away from the pseudo-code, the previous function would be actually written:
int THIS_USES_VARIABLES(void){
float x = 3.14;
float y = 9.0;
x = x - 0.14;
return ARE_THESE_EQUAL(x * x, y);
}
Note the differences. Now, we have to put what type the function returns before its name — thus we are saying that calling THIS_USES_VARIABLES() will give you back an int. An int is short for "integer" — that's a regular number (not a decimal), like 0, 5, -1, etc. So, we're assuming that calling ARE_THESE_EQUAL(x * x, y) will end up with an int (by convention, it would probably return 0 if the two are not equal or 1 if the two are equal), but if it does not then the program will fail to run (since you have told the computer that two different things are the same). Additionally, we now have to add parentheses after function names, even if they don't take any parameters — additionally, placing void inside instead of any variable names tells the compiler that there are definitely no arguments taken by the function. (This is technically not necessary in C++, but it is an element of habit from extensively using C.) Additionally, we have to put a type before the name of the variables too — we tell the computer that x and y have type float, which stands for "floating point number". This is a decimal number, which is necessary since we made x equal to 3.14 originally. (Notice: even though x eventually becomes an integer, we still need to define it as floating point since it starts out that way!) And finally, we have to put curly braces around the function and put a semicolon after each statement (instead of just putting each one on each line).
Just like our imaginary machine could decide based on a button push, the Arduino can decide based on anything. There are several "decision-making" constructs. One example is the if-statement:
int x_is_more_than = -1;
if(x > 2){
x_is_more_than = 2;
else if(x > 1){
x_is_more_than = 1;
else {
x_is_more_than = 0;
}
Here, if x is greater than 2 then x_is_more_than will get set to 2. If not, but if it is greater than 1 (else if) then x_is_more_than will get set to 1. If neither of those cases were true (else), x_is_more_than will get set to 0. This construct can be repeated over and over: so you can have just a standalone if, an if-else, an if-elseif, an if-elseif-elseif-elseif-else, or whatever else you want (provided that the first one is an if and the else, if it exists, comes last).
We can also do things over and over again. There are two kinds of loops: while and for loops. While loops are simple: they look like if-statements, and then run commands while their condition is true. (Note the double slashes indicate a comment, which is ignored by the computer.)
int x = 10; // Set up a variable
while(x > 0){ // WHILE x is greater than zero, do this:
DO_SOMETHING(); // First call DO_SOMETHING()
x = x - 1; // Then set x equal to x - 1 (subtract 1 from x)
}
For-loops have three parts. The first part is something they do once at the very start. This is like int x = 10; in the example above. The second part is just like the while loop condition: while it is true, the loop will be run. And finally, the last part is something they do every time at the end of each loop. This is like the x = x - 1; in our example. So, for-loops are just like while loops but with added features, so we can write our example more succinctly using a for-loop (note that it will have the same behavior as the previous example):
for(int x = 10; x > 0; x = x - 1){
DO_SOMETHING();
}
See the three parts in the top of the for loop? Now compare that code to the code before. Notice how they're similar?
Generally, programming is best illustrated by an example. Now that the basics are understood, let's look at an example of Arduino code which blinks a light:
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin 13 as an output.
pinMode(13, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(13, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
There are a few last Arduino-specific items of note here:
There is a special function, named setup, which runs once when you first turn on the Arduino. Note how it is defined: it returns nothing, so the return type is void, and here the programmer has opted to not place a void inside the parentheses after setup (this is the default Arduino sketch — not written by me). However, adding a void inside the parentheses would not change the outcome of the program.
There is another special function already defined named pinMode which changes the mode of a pin. 13 is the pin that would be hooked up to the LED, so by saying pinMode(13, OUTPUT) we are telling the Arduino that pin 13 will be used as an output (we will be powering things from pin 13). Another option is INPUT — if we were, say, reading a button press on that pin, then we'd write INPUT instead.
There is another special function, named loop, which runs indefinitely after setup gets run. Essentially, the Arduino runs setup, then loop, then loop again, then loop again, then loop again... and so on.
There is another special function, named digitalWrite, which writes a voltage to a pin. HIGH means on and LOW means off — so digitalWrite(13, HIGH) means "turn on pin 13".
There is one final special function used, called delay, which waits for the number of specified milliseconds. There are 1000 milliseconds in a second, so delay(1000) means "wait 1 second before proceeding".
Notice how complicated this seems to just blink a light! This is a problem I am actively trying to address as a running side-project: writing my own programming language targeting embedded systems like the Arduino. Funnily enough, a programming language is actually just a program in another programming language that understands how to read code and convert it into raw machine instructions. Of course this sounds like a turtles-all-the-way-down paradox — what was the first programming language written in? — but actually the very first programming languages are written directly on the computer itself (embedded into the hardware). While my language is not complete yet, the same example program would likely be written:
using Io, Signal, Time
main = Io:write 13, (Signal:fold Io:flipFlop, Time:every 1000)
While this may be slightly harder to grasp conceptually at first (it is written in the functional declarative style which is orthogonal to the to-do-list-esque imperative style), the program much more succinct and reads more like words: "Write to pin 13 the result of the flipFlop transform being applied to a pulse every 1000 ms". (Time:every generates the "pulse" every 1000 ms, and Signal:fold takes in the "pulse" signal and applies a function to that pulse every time it happens. The given function is Io:flipFlop, which simply switches between 0, 1, 0, 1, 0, 1...)
Of course, this introduction to programming was very brief and did not even scratch the surface of what C++ can do. (See the attached program at the top for more complex examples.) However, we can conclude a few basic programming principles that will be applied in almost any language or environment:
A program is just an instruction set to tell a machine what to do and how to do it
The machine does exactly what it is told to do: no more, no less
The machine can only do one thing at a time
And most importantly, if you tell the machine to do something incorrectly, it will do something incorrectly! Safety guards are rare.
When current moves through a wire, it generates a small magnetic field around that wire. This phenomenon is known as electromagnetism. We can harness this force to create powerful magnets that can be controlled via our electronic devices — to learn more about this, our class performed a series of experiments which are detailed in the lab writeup below.
This project was probably my favorite out of the whole year, and I was very proud once it was "completed". I write completed in quotes because I do plan to continue working on it — there are still a few issues in the software which have yet to be resolved, and I would like to add a few more features to it such as an auto-position-reset (instead of manually winding up the strings each time). This, I think, indicates that the project was a definite success, and even in this form the game was quite fun! To begin, I think my critical thinking was a big strong point in this project. The development process was rocky, to say the least, but I managed to figure out solutions every time the problems presented themselves. For example, just 3 days before the presentation I discovered that the gearmotors I was planning on using to move the lander did not have the torque to run slowly enough for the precision needed. This was at first a large blow, as I had essentially completed the entire hardware setup. However, I quickly disassembled the motor mounts, designed new ones to 3D print out the next day, modified the pulleys with a Dremel tool and scoured around for some alternative motors. I found two continuous rotation servos in an old robot, which I hastily gutted and rewrote the software to accommodate them. While this meant I had to scrap the infrared encoders I was planning on using (modifying them for the servos would be a process that I did not have the time for, given how soon the deadline was), the motors proved to be a fairly suitable replacement and they ended up working fine.
Additionally, I think my conscientious learning was a positive aspect to this project. There were just 3 weeks — from initial conception to presentation day — to get the project together, and given the complexity of this design I was rather worried that it would not be complete in time. However, I worked really hard on it and put in a lot of time outside class to make sure that I would get it done. (Indeed, it was finished the night before it was due; had I not planned a few days as extra time to refine, the aforementioned gearmotor problem would have sabotaged the success of the project fatally.) In the end, the proper schedule planning that was done helped make sure the project was as polished as it could be. Finally, I also believe that my communication was good in this project. While the physical presentation was very informal, I think this write-up (and the other documents it contains) is a good indicator of this project's communicational strength.
As usual, there were a few small details which could've been improved. Given this was a group project, I think the collaboration probably could've been improved a little. I ended up doing a lot of work on this project, which was by nature as we did not have much in-class time and someone had to work on it outside of class; however, I should've planned my work more carefully so that I would know exactly what needed to be done in class to maximize what little time we did have. (This also factors in to conscientious learning.) Also, I think my conscientious learning could've been improved in the workflow of the project. Because of the aforementioned in-school/out-of-school dichotomy, we ended up writing a lot of the software before the physical hardware was built. This is a horrible idea since software is best built incrementally, and likely this design style might have led to some of the issues that ended up plaguing the landing detection system later on.
Aside from the few small issues, I really think this project was a big success. I planned an ambitious design, worked hard to see it through, overcame the challenges and ended up with a great final project. I'm really happy with the way it turned out, and hope to have more projects like it in the future.