Home  |  Mechanical  |  Electrical  |  Programming  |  Results & Reflections  |  Parts  |  Pictures |  Team & Contact

 

Programming

There were three main tasks in the programming of the Ultimate Etch-A-Sketch:
1. Moving the stepper motors
2. Monitoring inputs / Setting LEDs
3. Function algorithms

Moving the stepper motors
-------------------------

Stepper motors are controlled from the Handyboard through the built-in H-Bridge (L239D). The H-Bridge has four inputs and four outputs, but by assuming that the user plugs their stepper motor coils across two outputs, the two inputs are mapped by the Handyboard to only one logical output. They are called 0,1,2,3. To control the motors bipolarally, we used the built-in fd() and bk() functions. (They stopped working halfway through for some reason, so we actually ended up using motor(x,100) and motor(x,-100). )

We made each motor (the horizontal motor and the vertical motor) a seperate process that would step every third millisecond. Why every third millisecond? Because we had three processes, each of which was given one millisecond to execute. This is the HandyBoard's understanding of "multitasking".

Mapping to actual speed of the motors was a little bothersome. Because we had three processes running, the program could only step a motor once every three milliseconds, giving us a true "speed" of 1/3ms. This was slow, but we decided that offloading the stepper motor control to an external stepper motor controller would take too many of our limited handyboard outputs.

The speed was variable. The amount of time to wait between steps (1/speed) was calculated in another process to maximize the speed of these motor processes. The sleep time (xSleepTime) was calculated from an integer value (xSpeed) that ranged from zero to an arbitrary maximum. The higher the number, the lower the sleep time, the faster the motor.

<code>
void xMotor(void)
{
/*Simple enough- move the x stepper.*/
int xState=0;

while(1)
{
while (xSpeed==0);
if (xSpeed < 0)
{
if (xState!=3) xState++;
else xState=0;
xPos++;
}
else if (xSpeed > 0)
{
if (xState!=0) xState--;
else xState=3;
xPos--;
}

if (xState==0)
{
motor(2,100);
motor(3,100);
}
else if (xState==1)
{
motor(2,-100);
motor(3,100);
}
else if (xState==2)
{
motor(2,-100);
motor(3,-100);
}
else if (xState==3)
{
motor(2,100);
motor(3,-100);
}

sleep (xSleepTime);

}
}
</code>

Monitoring Inputs / Setting LEDs
--------------------------------

The third process that was running, beside the two motor processes, would poll the inputs at every iteration (updateFunction). The polling function checked the analog inputs for button presses and also did the math for xSpeed => xSleepTime. If an analog input went true, the global currentFunction value would change and the polling function would return a "0" value to signal that whatever called it should stop whatever it was doing and go back to the beginning of the process.

It would also turn on an LED depending on which function was chosen, via the digital outputs. "Egad! Digital outputs on the Handyboard?!" you say? On the last page or two of the technical reference there is a description of how to convert some other-functioning pins to digital outputs.


Function Algorithms
-------------------

For the real Brains of the operation, see these functions. There were four functions:

0: The drawing function

All that this function did was to check the position of the joystick, then pass that position as a speed to the motors. Then return and wait until called again. There was a funny task in converting the analog values from the analog inputs to the proper motor speeds: The joystick position did not map directly to the value at the analog input. It was some funny exponential relationship. At first, we tried to model it. But then, after realizing how much computing time we were wasting doing these silly calculations, we generalized the function to two linear functions. Sure, we confused some of the mapping between joystick position and motor speed, but it was barely noticeable.

1: Geometric shapes

This function kept a state variable that would tell the function to alternate through four different simple shapes: Square, Triangle, Circle, and Squiggly Line. To make these precise shapes, we used a positioning function (move). The positioning function would move to a new location, relative to the location the pointer was at when the function was called. Because this positioning was relative, we never figured out how to make a circle. We think that we were really close to figuring it out, though.

2: Stick Figure

This function was a lot like the primitive shapes button, but drew a stick figure. It took a little while to execute, since it was more complex. (It also has the ability to write the name "Lynch", but after the brown-nosing flak we got, we took it out.)

3: Spiral of DOOM

Here the Etch-A-Sketch would start at the current position and make an increasingly large square. The results were much like the attempts of children to cover the screen completely so that they could see the internal components of the Etch-A-Sketch. We never let it run long enough to do the entire screen, though.


The final version of the entire code is attached (655 lines). There might also be some insightful comments in the code itself.