Tuesday, April 26, 2011

Encapsulate The Concept That Varies

One of my favorite Object-Oriented Design themes is "encapsulate the concept that varies". You may need an algorithm of some kind that needs to process data or run a calculation. There may be several solutions to the problem. The code that needs to make use of the algorithm should not need to know how it's implemented. The way the algorithm is used might be called its "public interface". If the thing we are building is a toaster, the method it uses to make the toast is something we don't know or care about. We just use the public interface by turning the dial and pushing the lever down.

I wrote some time ago that I'll need a robust, compact serial protocol for communications between the host and microcontroller. I'm still looking for something I can use that someone else wrote. In the meantime I need my computers communicating so I'm just using a basic character-based protocol. I intend to replace this later with a binary protocol of some kind hopefully with error checking.

The public interface is pretty simple. Each "request" and "response" consists of a "command" and an "argument" (or parameter depending on your perspective). Both elements are numbers (integers). The command is a number from 1 - 255. The argument is +/- 2 billion. The command may be something like "initialize program" or "set target period". The argument is a value for a set command. The logic on the host and microcontroller each have functions to send and receive this command/argument statement. The implementation of these functions is pretty simple, basically read/write (print) statements on the serial line.

In the future all I will need to change are these 4 functions. The logic that calls these functions will not need to change. What I could have done is issued print statements directly where I needed to in various points in the host software, for example. Then I'd need to find all those points later and rewrite them for the binary protocol. Instead, everything funnels through these functions that won't require an interface (signature) change. This is a pretty simple example of this sort of thing, for sure, but it illustrates the concept.

I wrote a simple shell program so I could type commands into the microcontroller (a benefit of the character-based protocol for development). I managed to string 2 move commands together and the steppers performed a 3-axis coordinated move for the first time. That was awesome. Time to move on to the host path generation software and start sending tool paths!

In my last post I had roughed out the LightManager. This is done now. It has a mode that is in effect when the host is sending a program to run (automatic mode). The up/down in/out lights flash rapidly and alternating like ambulance or snow plow lights. The left/right lights alternate more slowly and out of sync with the other lights like train crossing signals. It's pretty cool. I need to make a video of it.

Tuesday, April 19, 2011

LightManager

One great thing about this project is that I do a lot of back and forth between hardware and software work. It's not one monolithic software project. That would feel too much like work.

I opted not to buy the arcade buttons with the built in LEDs. It seems those buttons were designed for 12V systems and I would be using 5V. I probably could have modified them. I got an LED flashlight from a Yankee Swap last Christmas. It didn't work really at all but it had about 20 5mm white LEDs. Just what I needed. I drilled holes in my translucent arcade buttons, wired up the LEDs and used my favorite prototyping tool, the hot glue gun, to secure them:

Bottom of button with hole:



With LED wired and glued in:


The output pins on the Arduino (Sanguino) can provide up to 50ma of current. I didn't have any specs for the LEDs but used Ohm's law, my multimeter and some online calculators to determine what resistor to use. At 5V a 100 Ohm resistor will cap the current at 50ma. That plus the resistance of the LED itself should keep me well within a safe range and still give me plenty of brightness.

Then I wrote a basic version of my LightManager class to blink them on one at a time so I could determine if my wiring was good and which pin went to which light. Surprisingly I struggled with this. After all my years of programming I still make some amateur errors once in a while. I wrote a case/switch statement to control which light is on. In Java I have a template that lays out the structure for me, but I'm writing this in C and so I wrote it all out by hand. And I forgot my "break" statement for each case, so it totally didn't work. But I finally figured it out and discovered that my circuit design and soldering job was perfect. Here's a shot with one light on:

Friday, April 8, 2011

Buffered Movement

I've been hard at work on the firmware layer. In February I described the major software components. I now have the Controller and the VectorBuffer done. This is a significant step. Previously I had what I'm now calling "continuous" mode: you press and hold a button and one motor accelerates and maintains speed while the button is pressed. Releasing the button causes the motor to decelerate to a stop. This is one of two "manual" modes. The other I called "nudge" mode but I can't put that in my code, it's just not professional, so I'm calling it "discreet" mode now: one press of a button turns the motor a fixed amount. Sort of, the amount to turn will be determined by the position of the throttle control. So if the throttle is in the "1/1000" position, three presses of one button will move the mill head in the given direction by 0.003".

Continuous mode simply requires setting the current "vector" when a button is pressed and setting it again when the button is released. The reason discreet mode is significant is that this mode requires issuing 2 "move" commands: one to accelerate 1/2 the distance and another to decelerate the other 1/2 of the distance. (If the distance was a lot, I'd have it maintain maximum speed rather than accelerate continuously, but I expect moves to be 0.0005" to 0.020" so maximum speed would never be achieved.) The 2 moves are queued in the buffer and the StepperDriver pulls the next move off when it finishes the current move. That's the basis for "automatic" mode, or the main mode the system will be running in with the host computer feeding move after move into the buffer.

I struggled a bit with things again due to my lack of experience with C. I made several minor errors in design, but I made one big error in coding for C. Consider this variable declaration:

int steps;

This means the variable named "steps" stores "integers". But I didn't set the variable to any value - I didn't initialize it. In Java, if you were to print out the value of steps, you would always get zero. In C, at least on the compiler/microcontroller I am running this on, the value appears to be zero most of the time but would occasionally be some random value. My Vector class describes what direction and how far/fast to move. I didn't initialize the values that were to be zero and the behavior was really bizarre. I was really scratching my head looking for logic flaws. Finally I thought I'd try setting the zero values explicitly and that took care of it.