With all the initial components printed out and laser-cut, it’s time to write some code to control the 2-axis gimbal! The goal here is to control the dispenser to “draw” spiral like-shapes over the coffee grounds. Rather than drawing an exact spiral, we’ll be programming the servos to draw a series of concentric circles that cover the coffee grounds.
Step 1: Determine Servo Home Positions
I started things off by mounting the gimbal components to the servo horns as close to the middle of each servo’s sweep as possible. While I’m not needing all 180 degrees of rotation, it can’t hurt being as close to the middle as possible.
Utilizing the Arduino Servo library, I used a simple piece of code to control each servo’s position in order to manually find my home positions (level inner-chassis and vertical dispenser).
I started off with a guess of 90 degrees and adjusted the position for each servo until everything was aligned perfectly. I found that my dispenser was perfectly vertical at position 92, and the inner chassis was level at position 81.
Step 2: Draw a Square
Before we can tackle drawing concentric circles, we need to be able to draw a single circle, and before we can draw a circle, we need to be to draw a square. Baby steps!
Let’s start by figuring out how to draw the square shape shown below (imagine this is a top view, looking straight down the dispenser).
We can start by breaking down the square into four points. At each of these points, one servo will be at a maximum angle (alpha), and the other will be at it’s home position. We can plot these points on a chart as follows:
So how do we connect these points? This depends entirely on the shape we’d like to draw. For a square, all we have to do is connect them with straight lines, as follows:
Step 3: Draw a Circle
So how does drawing a square help us draw a circle? Let’s take our initial square path, but this time draw a circle that goes through all four points.
Considering the circle passes through the same four points as before, all that we need to change is the rate of change of each servo as it moves from position to position. So what’s the answer? Sine waves. By controlling the position of our servos with two sine waves (cos(x) and sin(x)), they will together draw a circle. Feel free to nerd out with me on the Unit Circle here.
With this in mind, I wrote Arduino code to breakdown the sine curves into a number of steps, and evaluate the servos’ positions with a cosine and sine function at each of these steps (theta). I defined a variable, sweepRange, that determines the range that each servo can sweep, represented by alpha max and alpha min above. Lastly, these sine curves are offset by each servo’s home position.
I utilized the Blink Without Delay sample code from Arduino to incorporate proper timing into my code that doesn’t use delays. This resulted in much smoother motion.
Below is an example of the code, followed by a GIF of the dispenser moving in a perfectly circular motion!
int microHome = 92; int standardHome = 81; int sweepRange = 20; float theta = 0; int steps = 180; float thetaStep = 6.2832 / steps; int microPos = sweepRange*(cos(theta)) + microHome; int standardPos = sweepRange*(sin(theta)) + standardHome;
Step 4: Draw Concentric Circles
Rather than drawing a true spiral, I’m going to simplify things and draw concentric circles, decreasing in size to represent an inward pour. The above code is modified so that after each complete circle, the sweepRange is decreased by a step-over value, and another circle is drawn. This process is repeated until the SweepRange variable hits 0.
Whew! That was fun. It’s a great feeling seeing something digital come to life, and I can finally start to see the light at the end of the tunnel.
Next Steps: Design a reservoir and pumping system to transfer the water to the dispenser